Evaluating external design & large designs

This forum is for posts that specifically focus on the Windows desktop version of Ngene (i.e. all version 1.x releases).

Moderators: Andrew Collins, Michiel Bliemer, johnr

Re: Evaluating external design & large designs

Postby Michiel Bliemer » Thu Apr 10, 2025 9:52 am

1. If you only specify one non-zero prior then of course Ngene cannot check for dominance because that attribute cannot be compared with anything. If you specify non-zero priors for only 2 attributes then Ngene will reject any design that has a dominant attribute based on only these 2 attributes. When you specify the preference order, it is always best to specify (almost all) attributes with a preference order. If some have unknown order, then it is unlikely that there is an issue with dominant alternatives. In any case, with the default column-based swapping algorithm it will be impossible to find a design with 660 rows without any dominant alternative. You will need to switch to the modified Federov algorithm using ;alg = mfederov. This is a row-based algorithm that can easily avoid dominant alternatives, but may not yield attribute level balance. As mentioned earlier, the modified Federov algorithm is slow and perhaps too slow for such a huge model and design. In your case, since not ALL of your attributes have a clear preference order, you may want to forego dominance checks as there will not be a major issue.

2. You can reformulate using reject constraints. For example:
;reject:
alt12.mode = 1 and alt1_is_pt = 0,
etc,

3. This is the easiest of all. You need to formulate a labelled experiment whereby alt1 is always mode=1, alt2 is always mode=2, and alt3 is always mode=3. You can randomise the order of the alternatives in the survey instrument. This also makes it much easier to specify alternative-specific coefficients without the need for all the interactions, and it also makes it much easier to specify that certain attributes only appear in certain alternatives. In other words, everything becomes much easier; you do not need the is_pt indicator anymore and you do not need the auxiliary model anymore. But from your first message, you wanted mode to be an attribute, and the only reason for doing this is to allow the same mode across multiple alternatives. But if you do not want this, then the solution is simply a labelled experiment. Much easier, see script below! And in a labelled experiment, there is no issue with dominant alternatives because you are no longer comparing bus versus bus but only bus versus car etc.

Code: Select all
Design
;alts = rail, car, bus, none
;rows = 660
;block = 55

;eff = (mnl,d)                                   
;alg = mfederov

;model:
U(rail)  = asc_rail
         + b_fm_rail.dummy[0|0|0|0|0|0|0|0|0|0] * fm[2,3,4,5,6,7,8,9,10,11,1]                                  ? First Mile dummy: 1 = walk 5m (base), 2 = walk 15m, 3 = Taxi 5m 12€, 4 = Taxi 15m 30€, 5 = Taxi 30m 50€, 6 = PT 10m 0€, 7 = PT 30m 0€, 8 = PT 50m 0€, 9 = PT 10m 3€, 10 = PT 30m 6€, 11 = PT 50m 9€
         + b_tt.dummy[0|0]                      * tt[2,3,1]                                                    ? time dummy: 1 = 7h (base), 2 = 8h, 3 = 9h
         + b_transfers_rail.dummy[0|0]          * transfers[2,3,1]                                             ? transfers dummy: 1 = 0 transfers, 2 = 1 transfer, 3 = 2 transfers
         + b_delay.dummy[0|0|0]                 * delay[2,3,4,1]                                               ? delay dummy: 1 = on time (base), 2 = 20% 1h, 3 = 20% 2h, 4 = 20% 3h
         + b_cost.dummy[0|0|0|0]                * cost[2,3,4,5,1]                                              ? cost dummy: 1 = 25€ (base), 2 = 50€, 3 = 100€, 4 = 150€, 5 = 200€
         + b_lm_rail.dummy[0|0|0|0|0|0|0|0|0|0] * lm[2,3,4,5,6,7,8,9,10,11,1]                                  ? LM dummy: 1 = walk 5m (base), 2 = walk 15m, 3 = Taxi 5m 12€, 4 = Taxi 15m 30€, 5 = Taxi 30m 50€, 6 = PT 10m 0€, 7 = PT 30m 0€, 8 = PT 50m 0€, 9 = PT 10m 3€, 10 = PT 30m 6€, 11 = PT 50m 9€
         + b_busfreq.dummy[0|0]                 * busfreq[2,3,1]                                               ? bus frequency: 1 = every 30m (base), 2 = every 60m, 3 = 3 times a day
         + b_busstop.dummy[0|0|0|0]             * busstop[2,3,4,5,1]                                           ? distance to bus stop: 1 = right at the hotel (base), 2 = 5min, 3 = 10min, 4 = 15min, 5 = 30min
         + b_hotel.dummy[0|0|0|0]               * hotel[2,3,4,5,1]                                             ? facilities at the hotel: 1 = nothing, 2 = E-Bikes, 3 = of (own) electric car for free, 4 = charging of (own) electric car for a market price, 5 = electric car for guests
         + b_transfers2_delay2_rail             * transfers.dummy[2] * delay.dummy[2]
         + b_transfers2_delay3_rail             * transfers.dummy[2] * delay.dummy[3]
         + b_transfers2_delay4_rail             * transfers.dummy[2] * delay.dummy[4]
         + b_transfers3_delay2_rail             * transfers.dummy[3] * delay.dummy[2]
         + b_transfers3_delay3_rail             * transfers.dummy[3] * delay.dummy[3]
         + b_transfers3_delay4_rail             * transfers.dummy[3] * delay.dummy[4]
         /

U(car)   = asc_car
         + b_tt.dummy                           * tt
         + b_delay.dummy                        * delay
         + b_cost.dummy                         * cost
         + b_busfreq.dummy                      * busfreq
         + b_busstop.dummy                      * busstop
         + b_hotel.dummy                        * hotel
         /

U(bus)   = asc_bus
         + b_fm_bus.dummy[0|0|0|0|0|0|0|0|0|0]  * fm     
         + b_tt.dummy                           * tt
         + b_transfers_bus.dummy[0|0]           * transfers
         + b_delay.dummy                        * delay
         + b_cost.dummy                         * cost
         + b_lm_bus.dummy[0|0|0|0|0|0|0|0|0|0]  * lm
         + b_busfreq.dummy                      * busfreq
         + b_busstop.dummy                      * busstop
         + b_hotel.dummy                        * hotel
         + b_transfers2_delay2_bus              * transfers.dummy[2] * delay.dummy[2]
         + b_transfers2_delay3_bus              * transfers.dummy[2] * delay.dummy[3]
         + b_transfers2_delay4_bus              * transfers.dummy[2] * delay.dummy[4]
         + b_transfers3_delay2_bus              * transfers.dummy[3] * delay.dummy[2]
         + b_transfers3_delay3_bus              * transfers.dummy[3] * delay.dummy[3]
         + b_transfers3_delay4_bus              * transfers.dummy[3] * delay.dummy[4]

$


Michiel
Michiel Bliemer
 
Posts: 1996
Joined: Tue Mar 31, 2009 4:13 pm

Re: Evaluating external design & large designs

Postby bartoszbursa » Wed Apr 16, 2025 4:49 pm

Thanks again, Michiel, this is extremely helpful!

I see the advantages of a labeled design - simpler code, easy to follow alternative-specific coefficients, no multiple interaction terms, etc.

However, there is one problem with labeled design in my specific case. As the final development of my design, which is getting to complex with these first/last mile attributes for the respondents, I want to show only 3 (2 real ones + none) out of 4 alternatives, which leads me to partial choice sets with modified Federov and the trick with an additional 9999 level for one of the attributes. Unfortunately, according to the manual, this works only if there is at least one non-dummy variable in the model. Is there any other way to do it? I thought of two ways:
(1) In labeled design, maybe I could add an artificial linear variable just for the sake of the trick, and then delete it from the design?
(2) in unlabeled design, add some kind of additional variable that "turns off" one level of mode (which will now be an attribute) every 25% of cases, but I am not sure how to start with that.

Bartosz
bartoszbursa
 
Posts: 11
Joined: Tue Mar 18, 2025 9:29 pm

Re: Evaluating external design & large designs

Postby Michiel Bliemer » Thu Apr 17, 2025 8:47 am

Yes it is possible to create partial choice set designs without using the external candidate set method described in the manual. This indeed involves rewriting the utility functions from labelled to unlabelled. For example, where you have 4 modes but you only show 3 modes in each choice task. So then you would specify three alternatives whereby 'mode' becomes a variable in the model and whereby you create an indicator variable in the same way as I proposed earlier.

This technique was applied in this paper:
https://onlinelibrary.wiley.com/doi/full/10.1002/hec.4666

If you want to use a labelled design, then yes you could also add an artificial variable for this purpose, but this is not the nicest way because the coefficient of this variable will still be considered in optimising the efficient design. But it would be a much easier approach.

Michiel
Michiel Bliemer
 
Posts: 1996
Joined: Tue Mar 31, 2009 4:13 pm

Re: Evaluating external design & large designs

Postby bartoszbursa » Thu Apr 17, 2025 10:18 pm

(1) I followed the syntax provided in the appendix to the paper by Thai et al., and all seems to be working ok. But could you please take a look at this and see if this code makes sense?

Some infos / changes to previous code:
- I did that with just one model (no aux & main as before)
- First and Last Mile attributes are now split into two: mode & cost (there's no time attr.) - both are alternative-specific
- cost for FM and LM depends on mode for FM/LM - additional conditions for that
- transfers attribute is alternative-specific
- no delay and hotel attributes in this code

(2) In your paper, everything was alternative-specific and every attribute appeared in every alternative. In my case, only FM, LM, and transfers are alt.-spec. And they only appear for RAIL and BUS main modes. This makes me a little confused about how many of these new dummy variables are supposed to be in relation to the old ones (from what I understand from your article, it should be n-1), and how that relates to the base levels in these old dummy variables.

(3) Design in this form is a bit unnatural, with all these new dummies for each level of FM, LM, and transfers. I understand that I can/should now bring it down manually to a more compact state, where I will have e.g. a single column for FM_COST, which will take values 1-8 depending on whether FM_COST_1-7 == 0/1, right?

(4) I am still also a bit confused about the dominance/repetition checking (asterisks) - should I use it in this case or not, and what does it have to do with introducing close-to-zero sign priors afterwards?

Code:
Code: Select all
Design
;alts = alt1*, alt2*, none
;rows = 60                                    ? 54 parms; number of alternatives = 2 (without none); minimum S = 54 / (2-1) = 54/1 = 54 ; practical S = 3*S_min = 162
?;block = 6


;eff = (mnl,d)                                   
;alg = swap
?;store = 1


;cond:

? Step 1&2: Introduce MODE (LABEL) attribute and INDICATOR
if(alt1.MODE = 1, alt1.RAIL = 1), if(alt1.MODE <> 1, alt1.RAIL = 0),
if(alt1.MODE = 3, alt1.BUS = 1), if(alt1.MODE <> 3, alt1.BUS = 0),

if(alt2.MODE = 1, alt2.RAIL = 1), if(alt2.MODE <> 1, alt2.RAIL = 0),
if(alt2.MODE = 3, alt2.BUS = 1), if(alt2.MODE <> 3, alt2.BUS = 0),

? Step 3: Introduce conditions for categorical variables with more than two levels
if(alt1.FM_MODE_BUS = 1, alt1.FM_MODE_TAXI = 0), if(alt1.FM_MODE_TAXI = 1, alt1.FM_MODE_BUS = 0),
if(alt2.FM_MODE_BUS = 1, alt2.FM_MODE_TAXI = 0), if(alt2.FM_MODE_TAXI = 1, alt2.FM_MODE_BUS = 0),

if(alt1.FM_COST_1 = 1, alt1.FM_COST_2 = 0), if(alt1.FM_COST_1 = 1, alt1.FM_COST_3 = 0), if(alt1.FM_COST_1 = 1, alt1.FM_COST_4 = 0), if(alt1.FM_COST_1 = 1, alt1.FM_COST_5 = 0), if(alt1.FM_COST_1 = 1, alt1.FM_COST_6 = 0), if(alt1.FM_COST_1 = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_COST_2 = 1, alt1.FM_COST_1 = 0), if(alt1.FM_COST_2 = 1, alt1.FM_COST_3 = 0), if(alt1.FM_COST_2 = 1, alt1.FM_COST_4 = 0), if(alt1.FM_COST_2 = 1, alt1.FM_COST_5 = 0), if(alt1.FM_COST_2 = 1, alt1.FM_COST_6 = 0), if(alt1.FM_COST_2 = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_COST_3 = 1, alt1.FM_COST_1 = 0), if(alt1.FM_COST_3 = 1, alt1.FM_COST_2 = 0), if(alt1.FM_COST_3 = 1, alt1.FM_COST_4 = 0), if(alt1.FM_COST_3 = 1, alt1.FM_COST_5 = 0), if(alt1.FM_COST_3 = 1, alt1.FM_COST_6 = 0), if(alt1.FM_COST_3 = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_COST_4 = 1, alt1.FM_COST_1 = 0), if(alt1.FM_COST_4 = 1, alt1.FM_COST_2 = 0), if(alt1.FM_COST_4 = 1, alt1.FM_COST_3 = 0), if(alt1.FM_COST_4 = 1, alt1.FM_COST_5 = 0), if(alt1.FM_COST_4 = 1, alt1.FM_COST_6 = 0), if(alt1.FM_COST_4 = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_COST_5 = 1, alt1.FM_COST_1 = 0), if(alt1.FM_COST_5 = 1, alt1.FM_COST_2 = 0), if(alt1.FM_COST_5 = 1, alt1.FM_COST_3 = 0), if(alt1.FM_COST_5 = 1, alt1.FM_COST_4 = 0), if(alt1.FM_COST_5 = 1, alt1.FM_COST_6 = 0), if(alt1.FM_COST_5 = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_COST_6 = 1, alt1.FM_COST_1 = 0), if(alt1.FM_COST_6 = 1, alt1.FM_COST_2 = 0), if(alt1.FM_COST_6 = 1, alt1.FM_COST_3 = 0), if(alt1.FM_COST_6 = 1, alt1.FM_COST_4 = 0), if(alt1.FM_COST_6 = 1, alt1.FM_COST_5 = 0), if(alt1.FM_COST_6 = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_COST_7 = 1, alt1.FM_COST_1 = 0), if(alt1.FM_COST_7 = 1, alt1.FM_COST_2 = 0), if(alt1.FM_COST_7 = 1, alt1.FM_COST_3 = 0), if(alt1.FM_COST_7 = 1, alt1.FM_COST_4 = 0), if(alt1.FM_COST_7 = 1, alt1.FM_COST_5 = 0), if(alt1.FM_COST_7 = 1, alt1.FM_COST_6 = 0),
if(alt2.FM_COST_1 = 1, alt2.FM_COST_2 = 0), if(alt2.FM_COST_1 = 1, alt2.FM_COST_3 = 0), if(alt2.FM_COST_1 = 1, alt2.FM_COST_4 = 0), if(alt2.FM_COST_1 = 1, alt2.FM_COST_5 = 0), if(alt2.FM_COST_1 = 1, alt2.FM_COST_6 = 0), if(alt2.FM_COST_1 = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_COST_2 = 1, alt2.FM_COST_1 = 0), if(alt2.FM_COST_2 = 1, alt2.FM_COST_3 = 0), if(alt2.FM_COST_2 = 1, alt2.FM_COST_4 = 0), if(alt2.FM_COST_2 = 1, alt2.FM_COST_5 = 0), if(alt2.FM_COST_2 = 1, alt2.FM_COST_6 = 0), if(alt2.FM_COST_2 = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_COST_3 = 1, alt2.FM_COST_1 = 0), if(alt2.FM_COST_3 = 1, alt2.FM_COST_2 = 0), if(alt2.FM_COST_3 = 1, alt2.FM_COST_4 = 0), if(alt2.FM_COST_3 = 1, alt2.FM_COST_5 = 0), if(alt2.FM_COST_3 = 1, alt2.FM_COST_6 = 0), if(alt2.FM_COST_3 = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_COST_4 = 1, alt2.FM_COST_1 = 0), if(alt2.FM_COST_4 = 1, alt2.FM_COST_2 = 0), if(alt2.FM_COST_4 = 1, alt2.FM_COST_3 = 0), if(alt2.FM_COST_4 = 1, alt2.FM_COST_5 = 0), if(alt2.FM_COST_4 = 1, alt2.FM_COST_6 = 0), if(alt2.FM_COST_4 = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_COST_5 = 1, alt2.FM_COST_1 = 0), if(alt2.FM_COST_5 = 1, alt2.FM_COST_2 = 0), if(alt2.FM_COST_5 = 1, alt2.FM_COST_3 = 0), if(alt2.FM_COST_5 = 1, alt2.FM_COST_4 = 0), if(alt2.FM_COST_5 = 1, alt2.FM_COST_6 = 0), if(alt2.FM_COST_5 = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_COST_6 = 1, alt2.FM_COST_1 = 0), if(alt2.FM_COST_6 = 1, alt2.FM_COST_2 = 0), if(alt2.FM_COST_6 = 1, alt2.FM_COST_3 = 0), if(alt2.FM_COST_6 = 1, alt2.FM_COST_4 = 0), if(alt2.FM_COST_6 = 1, alt2.FM_COST_5 = 0), if(alt2.FM_COST_6 = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_COST_7 = 1, alt2.FM_COST_1 = 0), if(alt2.FM_COST_7 = 1, alt2.FM_COST_2 = 0), if(alt2.FM_COST_7 = 1, alt2.FM_COST_3 = 0), if(alt2.FM_COST_7 = 1, alt2.FM_COST_4 = 0), if(alt2.FM_COST_7 = 1, alt2.FM_COST_5 = 0), if(alt2.FM_COST_7 = 1, alt2.FM_COST_6 = 0),

if(alt1.TRANSFERS_1 = 1, alt1.TRANSFERS_2 = 0), if(alt1.TRANSFERS_2 = 1, alt1.TRANSFERS_1 = 0),
if(alt2.TRANSFERS_1 = 1, alt2.TRANSFERS_2 = 0), if(alt2.TRANSFERS_2 = 1, alt2.TRANSFERS_1 = 0),

if(alt1.LM_MODE_BUS = 1, alt1.LM_MODE_TAXI = 0), if(alt1.LM_MODE_TAXI = 1, alt1.LM_MODE_BUS = 0),
if(alt2.LM_MODE_BUS = 1, alt2.LM_MODE_TAXI = 0), if(alt2.LM_MODE_TAXI = 1, alt2.LM_MODE_BUS = 0),

if(alt1.LM_COST_1 = 1, alt1.LM_COST_2 = 0), if(alt1.LM_COST_1 = 1, alt1.LM_COST_3 = 0), if(alt1.LM_COST_1 = 1, alt1.LM_COST_4 = 0), if(alt1.LM_COST_1 = 1, alt1.LM_COST_5 = 0), if(alt1.LM_COST_1 = 1, alt1.LM_COST_6 = 0), if(alt1.LM_COST_1 = 1, alt1.LM_COST_7 = 0),
if(alt1.LM_COST_2 = 1, alt1.LM_COST_1 = 0), if(alt1.LM_COST_2 = 1, alt1.LM_COST_3 = 0), if(alt1.LM_COST_2 = 1, alt1.LM_COST_4 = 0), if(alt1.LM_COST_2 = 1, alt1.LM_COST_5 = 0), if(alt1.LM_COST_2 = 1, alt1.LM_COST_6 = 0), if(alt1.LM_COST_2 = 1, alt1.LM_COST_7 = 0),
if(alt1.LM_COST_3 = 1, alt1.LM_COST_1 = 0), if(alt1.LM_COST_3 = 1, alt1.LM_COST_2 = 0), if(alt1.LM_COST_3 = 1, alt1.LM_COST_4 = 0), if(alt1.LM_COST_3 = 1, alt1.LM_COST_5 = 0), if(alt1.LM_COST_3 = 1, alt1.LM_COST_6 = 0), if(alt1.LM_COST_3 = 1, alt1.LM_COST_7 = 0),
if(alt1.LM_COST_4 = 1, alt1.LM_COST_1 = 0), if(alt1.LM_COST_4 = 1, alt1.LM_COST_2 = 0), if(alt1.LM_COST_4 = 1, alt1.LM_COST_3 = 0), if(alt1.LM_COST_4 = 1, alt1.LM_COST_5 = 0), if(alt1.LM_COST_4 = 1, alt1.LM_COST_6 = 0), if(alt1.LM_COST_4 = 1, alt1.LM_COST_7 = 0),
if(alt1.LM_COST_5 = 1, alt1.LM_COST_1 = 0), if(alt1.LM_COST_5 = 1, alt1.LM_COST_2 = 0), if(alt1.LM_COST_5 = 1, alt1.LM_COST_3 = 0), if(alt1.LM_COST_5 = 1, alt1.LM_COST_4 = 0), if(alt1.LM_COST_5 = 1, alt1.LM_COST_6 = 0), if(alt1.LM_COST_5 = 1, alt1.LM_COST_7 = 0),
if(alt1.LM_COST_6 = 1, alt1.LM_COST_1 = 0), if(alt1.LM_COST_6 = 1, alt1.LM_COST_2 = 0), if(alt1.LM_COST_6 = 1, alt1.LM_COST_3 = 0), if(alt1.LM_COST_6 = 1, alt1.LM_COST_4 = 0), if(alt1.LM_COST_6 = 1, alt1.LM_COST_5 = 0), if(alt1.LM_COST_6 = 1, alt1.LM_COST_7 = 0),
if(alt1.LM_COST_7 = 1, alt1.LM_COST_1 = 0), if(alt1.LM_COST_7 = 1, alt1.LM_COST_2 = 0), if(alt1.LM_COST_7 = 1, alt1.LM_COST_3 = 0), if(alt1.LM_COST_7 = 1, alt1.LM_COST_4 = 0), if(alt1.LM_COST_7 = 1, alt1.LM_COST_5 = 0), if(alt1.LM_COST_7 = 1, alt1.LM_COST_6 = 0),
if(alt2.LM_COST_1 = 1, alt2.LM_COST_2 = 0), if(alt2.LM_COST_1 = 1, alt2.LM_COST_3 = 0), if(alt2.LM_COST_1 = 1, alt2.LM_COST_4 = 0), if(alt2.LM_COST_1 = 1, alt2.LM_COST_5 = 0), if(alt2.LM_COST_1 = 1, alt2.LM_COST_6 = 0), if(alt2.LM_COST_1 = 1, alt2.LM_COST_7 = 0),
if(alt2.LM_COST_2 = 1, alt2.LM_COST_1 = 0), if(alt2.LM_COST_2 = 1, alt2.LM_COST_3 = 0), if(alt2.LM_COST_2 = 1, alt2.LM_COST_4 = 0), if(alt2.LM_COST_2 = 1, alt2.LM_COST_5 = 0), if(alt2.LM_COST_2 = 1, alt2.LM_COST_6 = 0), if(alt2.LM_COST_2 = 1, alt2.LM_COST_7 = 0),
if(alt2.LM_COST_3 = 1, alt2.LM_COST_1 = 0), if(alt2.LM_COST_3 = 1, alt2.LM_COST_2 = 0), if(alt2.LM_COST_3 = 1, alt2.LM_COST_4 = 0), if(alt2.LM_COST_3 = 1, alt2.LM_COST_5 = 0), if(alt2.LM_COST_3 = 1, alt2.LM_COST_6 = 0), if(alt2.LM_COST_3 = 1, alt2.LM_COST_7 = 0),
if(alt2.LM_COST_4 = 1, alt2.LM_COST_1 = 0), if(alt2.LM_COST_4 = 1, alt2.LM_COST_2 = 0), if(alt2.LM_COST_4 = 1, alt2.LM_COST_3 = 0), if(alt2.LM_COST_4 = 1, alt2.LM_COST_5 = 0), if(alt2.LM_COST_4 = 1, alt2.LM_COST_6 = 0), if(alt2.LM_COST_4 = 1, alt2.LM_COST_7 = 0),
if(alt2.LM_COST_5 = 1, alt2.LM_COST_1 = 0), if(alt2.LM_COST_5 = 1, alt2.LM_COST_2 = 0), if(alt2.LM_COST_5 = 1, alt2.LM_COST_3 = 0), if(alt2.LM_COST_5 = 1, alt2.LM_COST_4 = 0), if(alt2.LM_COST_5 = 1, alt2.LM_COST_6 = 0), if(alt2.LM_COST_5 = 1, alt2.LM_COST_7 = 0),
if(alt2.LM_COST_6 = 1, alt2.LM_COST_1 = 0), if(alt2.LM_COST_6 = 1, alt2.LM_COST_2 = 0), if(alt2.LM_COST_6 = 1, alt2.LM_COST_3 = 0), if(alt2.LM_COST_6 = 1, alt2.LM_COST_4 = 0), if(alt2.LM_COST_6 = 1, alt2.LM_COST_5 = 0), if(alt2.LM_COST_6 = 1, alt2.LM_COST_7 = 0),
if(alt2.LM_COST_7 = 1, alt2.LM_COST_1 = 0), if(alt2.LM_COST_7 = 1, alt2.LM_COST_2 = 0), if(alt2.LM_COST_7 = 1, alt2.LM_COST_3 = 0), if(alt2.LM_COST_7 = 1, alt2.LM_COST_4 = 0), if(alt2.LM_COST_7 = 1, alt2.LM_COST_5 = 0), if(alt2.LM_COST_7 = 1, alt2.LM_COST_6 = 0),

? Study-specific conditions
if(alt1.FM_MODE_BUS = 1, alt1.FM_COST_4 = 0), if(alt1.FM_MODE_BUS = 1, alt1.FM_COST_5 = 0), if(alt1.FM_MODE_BUS = 1, alt1.FM_COST_6 = 0), if(alt1.FM_MODE_BUS = 1, alt1.FM_COST_7 = 0),
if(alt1.FM_MODE_TAXI = 1, alt1.FM_COST_1 = 0), if(alt1.FM_MODE_TAXI = 1, alt1.FM_COST_2 = 0), if(alt1.FM_MODE_TAXI = 1, alt1.FM_COST_3 = 0),

if(alt2.FM_MODE_BUS = 1, alt2.FM_COST_4 = 0), if(alt2.FM_MODE_BUS = 1, alt2.FM_COST_5 = 0), if(alt2.FM_MODE_BUS = 1, alt2.FM_COST_6 = 0), if(alt2.FM_MODE_BUS = 1, alt2.FM_COST_7 = 0),
if(alt2.FM_MODE_TAXI = 1, alt2.FM_COST_1 = 0), if(alt2.FM_MODE_TAXI = 1, alt2.FM_COST_2 = 0), if(alt2.FM_MODE_TAXI = 1, alt2.FM_COST_3 = 0)



;model:

U(alt1)  = b_mode.dummy[0|0]                  * MODE[1,3,2]                                                  ? main mode dummy: 1 = rail, 2 = car (base), 3 = bus

         + b_fm_mode_bus_rail[0]              * FM_MODE_BUS[0,1]                 * RAIL[0,1]                 ? (naming for old dummies) First Mile mode dummy: 1 = walk (base), 2 = bus, 3 = taxi
         + b_fm_mode_taxi_rail[0]             * FM_MODE_TAXI[0,1]                * RAIL[0,1]
         + b_fm_mode_bus_bus[0]               * FM_MODE_BUS[0,1]                 * BUS[0,1]
         + b_fm_mode_taxi_bus[0]              * FM_MODE_TAXI[0,1]                * BUS[0,1]

         + b_fm_cost_1_rail[0]                * FM_COST_1[0,1]                   * RAIL[0,1]                 ? (naming for old dummies) First Mile cost dummy (1-4 for bus, 5-8 for taxi): 1 = 0€ (base), 2 = 3€, 3 = 6€, 4 = 9€, 5 = 10€, 6 = 20€, 7 = 30€, 8 = 40€
         + b_fm_cost_2_rail[0]                * FM_COST_2[0,1]                   * RAIL[0,1]
         + b_fm_cost_3_rail[0]                * FM_COST_3[0,1]                   * RAIL[0,1]
         + b_fm_cost_4_rail[0]                * FM_COST_4[0,1]                   * RAIL[0,1]
         + b_fm_cost_5_rail[0]                * FM_COST_5[0,1]                   * RAIL[0,1]
         + b_fm_cost_6_rail[0]                * FM_COST_6[0,1]                   * RAIL[0,1]
         + b_fm_cost_7_rail[0]                * FM_COST_7[0,1]                   * RAIL[0,1]
         + b_fm_cost_1_bus[0]                 * FM_COST_1[0,1]                   * BUS[0,1]
         + b_fm_cost_2_bus[0]                 * FM_COST_2[0,1]                   * BUS[0,1]
         + b_fm_cost_3_bus[0]                 * FM_COST_3[0,1]                   * BUS[0,1]
         + b_fm_cost_4_bus[0]                 * FM_COST_4[0,1]                   * BUS[0,1]
         + b_fm_cost_5_bus[0]                 * FM_COST_5[0,1]                   * BUS[0,1]
         + b_fm_cost_6_bus[0]                 * FM_COST_6[0,1]                   * BUS[0,1]
         + b_fm_cost_7_bus[0]                 * FM_COST_7[0,1]                   * BUS[0,1]

         + b_tt.dummy[0|0]                    * TT[2,3,1]                                                    ? time dummy: 1 = 7h (base), 2 = 8h, 3 = 9h

         + b_transfers_1_rail[0]              * TRANSFERS_1[0,1]                 * RAIL[0,1]
         + b_transfers_2_rail[0]              * TRANSFERS_2[0,1]                 * RAIL[0,1]
         + b_transfers_1_bus[0]               * TRANSFERS_1[0,1]                 * BUS[0,1]
         + b_transfers_2_bus[0]               * TRANSFERS_2[0,1]                 * BUS[0,1]

         + b_cost.dummy[0|0|0|0]              * COST[2,3,4,5,1]                                              ? cost dummy: 1 = 25€ (base), 2 = 50€, 3 = 100€, 4 = 150€, 5 = 200€

         + b_lm_mode_bus_rail[0]              * LM_MODE_BUS[0,1]                 * RAIL[0,1]                 ? (naming for old dummies)Last Mile mode dummy: 1 = walk (base), 2 = bus, 3 = taxi
         + b_lm_mode_taxi_rail[0]             * LM_MODE_TAXI[0,1]                * RAIL[0,1]
         + b_lm_mode_bus_bus[0]               * LM_MODE_BUS[0,1]                 * BUS[0,1]
         + b_lm_mode_taxi_bus[0]              * LM_MODE_TAXI[0,1]                * BUS[0,1]

         + b_lm_cost_1_rail[0]                * LM_COST_1[0,1]                   * RAIL[0,1]                 ? (naming for old dummies)Last Mile cost dummy (1-4 for bus, 5-8 for taxi): 1 = 0€ (base), 2 = 3€, 3 = 6€, 4 = 9€, 5 = 10€, 6 = 20€, 7 = 30€, 8 = 40€
         + b_lm_cost_2_rail[0]                * LM_COST_2[0,1]                   * RAIL[0,1]
         + b_lm_cost_3_rail[0]                * LM_COST_3[0,1]                   * RAIL[0,1]
         + b_lm_cost_4_rail[0]                * LM_COST_4[0,1]                   * RAIL[0,1]
         + b_lm_cost_5_rail[0]                * LM_COST_5[0,1]                   * RAIL[0,1]
         + b_lm_cost_6_rail[0]                * LM_COST_6[0,1]                   * RAIL[0,1]
         + b_lm_cost_7_rail[0]                * LM_COST_7[0,1]                   * RAIL[0,1]
         + b_lm_cost_1_bus[0]                 * LM_COST_1[0,1]                   * BUS[0,1]
         + b_lm_cost_2_bus[0]                 * LM_COST_2[0,1]                   * BUS[0,1]
         + b_lm_cost_3_bus[0]                 * LM_COST_3[0,1]                   * BUS[0,1]
         + b_lm_cost_4_bus[0]                 * LM_COST_4[0,1]                   * BUS[0,1]
         + b_lm_cost_5_bus[0]                 * LM_COST_5[0,1]                   * BUS[0,1]
         + b_lm_cost_6_bus[0]                 * LM_COST_6[0,1]                   * BUS[0,1]
         + b_lm_cost_7_bus[0]                 * LM_COST_7[0,1]                   * BUS[0,1]

         + b_busfreq.dummy[0|0]               * BUSFREQ[2,3,1]                                               ? bus frequency: 1 = every 30m (base), 2 = every 60m, 3 = 3 times a day
         + b_busstop.dummy[0|0|0|0]           * BUSSTOP[2,3,4,5,1]                                           ? distance to bus stop: 1 = right at the hotel (base), 2 = 5min, 3 = 10min, 4 = 15min, 5 = 30min
         /

U(alt2)  = b_mode.dummy                       * MODE
         + b_fm_mode_bus_rail                 * FM_MODE_BUS                      * RAIL
         + b_fm_mode_taxi_rail                * FM_MODE_TAXI                     * RAIL
         + b_fm_mode_bus_bus                  * FM_MODE_BUS                      * BUS
         + b_fm_mode_taxi_bus                 * FM_MODE_TAXI                     * BUS

         + b_fm_cost_1_rail                   * FM_COST_1                        * RAIL
         + b_fm_cost_2_rail                   * FM_COST_2                        * RAIL     
         + b_fm_cost_3_rail                   * FM_COST_3                        * RAIL     
         + b_fm_cost_4_rail                   * FM_COST_4                        * RAIL     
         + b_fm_cost_5_rail                   * FM_COST_5                        * RAIL     
         + b_fm_cost_6_rail                   * FM_COST_6                        * RAIL     
         + b_fm_cost_7_rail                   * FM_COST_7                        * RAIL     
         + b_fm_cost_1_bus                    * FM_COST_1                        * BUS     
         + b_fm_cost_2_bus                    * FM_COST_2                        * BUS     
         + b_fm_cost_3_bus                    * FM_COST_3                        * BUS     
         + b_fm_cost_4_bus                    * FM_COST_4                        * BUS     
         + b_fm_cost_5_bus                    * FM_COST_5                        * BUS     
         + b_fm_cost_6_bus                    * FM_COST_6                        * BUS     
         + b_fm_cost_7_bus                    * FM_COST_7                        * BUS     

         + b_tt.dummy                         * TT

         + b_transfers_1_rail                 * TRANSFERS_1                      * RAIL     
         + b_transfers_2_rail                 * TRANSFERS_2                      * RAIL     
         + b_transfers_1_bus                  * TRANSFERS_1                      * BUS     
         + b_transfers_2_bus                  * TRANSFERS_2                      * BUS     

         + b_cost.dummy                       * COST

         + b_lm_mode_bus_rail                 * LM_MODE_BUS                      * RAIL
         + b_lm_mode_taxi_rail                * LM_MODE_TAXI                     * RAIL     
         + b_lm_mode_bus_bus                  * LM_MODE_BUS                      * BUS     
         + b_lm_mode_taxi_bus                 * LM_MODE_TAXI                     * BUS     

         + b_lm_cost_1_rail                   * LM_COST_1                        * RAIL
         + b_lm_cost_2_rail                   * LM_COST_2                        * RAIL     
         + b_lm_cost_3_rail                   * LM_COST_3                        * RAIL     
         + b_lm_cost_4_rail                   * LM_COST_4                        * RAIL     
         + b_lm_cost_5_rail                   * LM_COST_5                        * RAIL     
         + b_lm_cost_6_rail                   * LM_COST_6                        * RAIL     
         + b_lm_cost_7_rail                   * LM_COST_7                        * RAIL     
         + b_lm_cost_1_bus                    * LM_COST_1                        * BUS     
         + b_lm_cost_2_bus                    * LM_COST_2                        * BUS     
         + b_lm_cost_3_bus                    * LM_COST_3                        * BUS     
         + b_lm_cost_4_bus                    * LM_COST_4                        * BUS     
         + b_lm_cost_5_bus                    * LM_COST_5                        * BUS     
         + b_lm_cost_6_bus                    * LM_COST_6                        * BUS     
         + b_lm_cost_7_bus                    * LM_COST_7                        * BUS     

         + b_busfreq.dummy                    * BUSFREQ
         + b_busstop.dummy                    * BUSSTOP

$


Many thanks
Bartosz
bartoszbursa
 
Posts: 11
Joined: Tue Mar 18, 2025 9:29 pm

Re: Evaluating external design & large designs

Postby Michiel Bliemer » Fri Apr 18, 2025 9:31 am

I am reaching the limits of the advice I can give here. Your script is very complex and each time it takes me a lot of time trying to understand your model as I am not intimately familiar with your study. So perhaps you can formulate questions more specifically related to Ngene and not the formulation of model or utility functions themselves? In our paper we used the indicator variable with which we could turn attributes on and off in the utility functions. So attributes could be generic of alternative-specific (or have alternative-specific levels), that would not matter.

Regarding dominance checks, these are only useful for unlabelled alternatives. If there are no issues with design generation when you include them, then you can keep the asterisks as there is no harm in doing so; if they are not relevant, then Ngene will automatically ignore them.

Michiel
Michiel Bliemer
 
Posts: 1996
Joined: Tue Mar 31, 2009 4:13 pm

Re: Evaluating external design & large designs

Postby bartoszbursa » Fri Apr 18, 2025 4:41 pm

You're right. I am sorry for flooding you with questions that are obviously study-specific and not directly related to Ngene.

Now more concerning Ngene:
(1) Is the trick with two models that you used a few posts ago necessary? You wrote that you "could not do that directly because cannot introduce dummy variables that only appear in an interaction." But isn't it what is happening in the code in your health study? You introduced the indicators in the model such as HOSP or COMM for pharmacy types that only appear in an interaction, without an auxiliary model to introduce them before the main model.
(2) I should only multiply those attributes with a MODE indicator that I want to be alternative-specific. If, say, TIME is to be generic, I leave it as it is, as there is no need to turn it on/off depending on mode, right?
(3) For dummies that initially have number of levels n>2, I end up now with n-1 new dummies (say, COST_10 [0/1], COST_20 [0/1], ...). As this is unpractical to implement in an online survey tool, I guess that after the design is generated, it is ok collapse these binary dummies back into a single categorical variable with multiple levels, and use this design in the online survey tool. Am I correct here?
(4) An extra one regarding your paper - you optimized the design for both the d-error and the a-error in the proportion 13:2 (;eff = 13*(mnl,d) + 2*(mnl,a)). How would you come up with these values (13 and 2), is there any way to calculate that?

Again, thank you so much for your hugely valuable advice.

Bartosz
bartoszbursa
 
Posts: 11
Joined: Tue Mar 18, 2025 9:29 pm

Re: Evaluating external design & large designs

Postby Michiel Bliemer » Sat Apr 19, 2025 8:51 am

1) You can introduce indicator variables without an auxiliary model, but you cannot introduce dummy variables THAT ONLY OCCUR IN AN INTERACTION directly in the utility function in Ngene. For example, you cannot do this: b1.dummy[..] * X[1,2,3] * Y[1,2,3], since Ngene first needs to create the dummy variables for X and Y separately, which is done by specifying them first as a main effect. In your case, some of your dummy variables do not appear as a main effect and therefore first need to be defined. This is a current limitation in the syntax of Ngene and it admittedly a bit ugly. We are working on a new property ;attributes, whereby we allow specifying all attributes before adding them in utility functions, which overcomes this issue in a nicer way. But for now, the auxiliary model is needed to simply define dummy variables that only appear in an interaction.

2) The typical way to create alternative-specific coefficients is to use labelled alternatives and specify something like:

U(car) = b1.dummy[0|0] * X[1,2,3] + ... /
U(train) = b2.dummy[0|0] * X

Here, the same attribute (X) has different alternative-specific coefficients (b1 and b2). This is by far the easiest.

If you want to do the same in an unlabelled formulation, then indeed you will need to make a lot of interaction effects to turn coefficients on or off depending on the mode.

3) Yes you are correct. If you specify b1.dummy[0|0] * X[1,2,3], then the DESIGN will simply refer to levels 1,2,3 that you can use in the survey instrument, while underneath the model gets translated into b1_1*(X==1) + b2_2*(X==2). Those dummy variables are only used in the utility function, not in the survey.

4) We wanted a balance between D-error and A-error. The A-error was approximately 6.5 times larger than the D-error, so we scaled them. We could have used 6.5*(mnl,d) + 1*(mnl,a), but I liked rounded numbers better so I multiplied the entire objective function by 2 (which yields the same result).

Michiel
Michiel Bliemer
 
Posts: 1996
Joined: Tue Mar 31, 2009 4:13 pm

Re: Evaluating external design & large designs

Postby bartoszbursa » Thu Apr 24, 2025 10:44 pm

Thanks again. Not all use cases are covered by the manual, and I really appreciate your advices.

1) That would be quite helpful and make coding easier. One last time regarding the difference between dummy and indicator variables. I can introduce binary indicator variables like those in your paper without defining them before in an aux. model, event though they are essentially dummy variables (with just two levels 0 and 1), and even though they appear only in an interaction with other variables (to turn them on/off). I just implemented that into my code and it works as in the code in your paper. But I can't do that with other "non-indicator" dummy variables - is it because they might have more levels than just two (as it is for the indicator variables) or what is the reason for that?

2) I am aware of that, but labeled design is not possible since I need partial choice sets (2 out of 3), and I can't do that with the candidate sets and Modified Fedorov algorithm as I have only dummy variables in my study. So I need to go unlabeled.

3) This will sound silly, but it's the first time I'm going to use output from Ngene in a real study and I just don't want to make any foolish mistakes here. I optimized my unlabeled design with indicators in Ngene, following you health economics paper. No errors or warnings, all looks fine. Now, the design table in Ngene contains columns for (1) variables that have generic coefficients in my utility functions (e.g. time and cost in my case), but also for (2) indicators (different modes in my case), and (3) new dummies for categorical variables that have more than two levels and which have alternative-specific coefficients, and (4) after the "block" column, a series of columns for all interactions in my model.
My understanding is that in order to have a design table that can be used in a survey tool: I keep (1), I delete (2) and (4), and collapse (3) back into a single categorical variable with many levels. And so I get a compact table with only those columns that I use in the survey. Is that correct?

4) Could you please elaborate a little more on this balance between D and A-error. Is there any (practical or theoretical) reason for having such a balance?

Thank you
Bartosz
bartoszbursa
 
Posts: 11
Joined: Tue Mar 18, 2025 9:29 pm

Re: Evaluating external design & large designs

Postby Michiel Bliemer » Fri Apr 25, 2025 9:35 am

1)
If you have 2 levels, and level 1 is the base, then you create 1 variable: X1=1 if level 1 and X1=0 if level 0. In this particular case, X1 is simply an indicator.
Now suppose that you have 3 levels, and level 3 is the base, then you create 2 variables: (X1,X2)=(1,0) if level 1, (X1,X2)=(0,1) if level 2, and (X1,X2)=(0,0) if level 3. This is clearly not a simple indicator variable.
Note that this is not Ngene-specific, this is just how dummy coding works.

3)
I believe this is correct.

4)
I essentially always use a D-efficient design because such a design is efficient independent of the units of the attributes, whereas an A-efficient design depends on the units. In this paper we used a combination because we wanted a bit more information pushed towards estimating the constants because this was a partial choice set design that we wanted to compare with a full choice set design, and the diagonals of the covariance matrix indicated that the constants had larger variances and therefore including the A-error did the trick. This is all quite technical and not common at all, so I would not do this in your case and just use the D-error.

Our new manual, available on https://files.choice-metrics.com/NgeneManual.pdf, has been completely rewritten. While this is the manual for Ngene Online, almost all syntax will also work in Ngene 1.X for Windows (except for a few shortcuts), so you may find this a useful resource.

Michiel
Michiel Bliemer
 
Posts: 1996
Joined: Tue Mar 31, 2009 4:13 pm

Re: Evaluating external design & large designs

Postby bartoszbursa » Sat Apr 26, 2025 1:04 am

Thanks again for your help, Michiel.

I have just flipped through the new manual and it is absolutely great - so much better and easier to follow than the previous one. I love the new chapters e.g. library of designs, auxiliary models, etc. Great work! We will be definitely switching to the new online Ngene for the next study.

I am still investigating the unlabeled design with partial choice sets before I run the pilot. And I noticed that while it is balanced, it is not balanced in the way I would like it to be. I explain it on a simplified example below.

I have 2 alts (alt1,alt2) in Ngene, but in reality 3 alternatives controlled by the label attribute MODE[rail, car, coach]. I created indicator variables RAIL[0,1] and COACH[0,1] to turn on/off the variable that is specific for RAIL and COACH - which is here "first mile mode". This attribute has 3 levels [walk,bus,taxi], with walk being base, so I created 2 new variables FM_MODE_BUS[0,1] and FM_MODE_TAXI[0,1]. I have no indicator for CAR as there are no car-specific variables to turn on/off.

Code: Select all
Design
;alts = alt1*, alt2*, none
;rows = 60                                    ? 54 parms; number of alternatives = 2 (without none); minimum S = 54 / (2-1) = 54/1 = 54
;block = 5


;eff = (mnl,d)
;alg = swap
?;store = 1


;cond:

? Step 1&2: Introduce MODE (LABEL) attribute and INDICATOR
if(alt1.MODE = 1, alt1.RAIL = 1), if(alt1.MODE <> 1, alt1.RAIL = 0),
if(alt1.MODE = 3, alt1.COACH = 1), if(alt1.MODE <> 3, alt1.COACH = 0),

if(alt2.MODE = 1, alt2.RAIL = 1), if(alt2.MODE <> 1, alt2.RAIL = 0),
if(alt2.MODE = 3, alt2.COACH = 1), if(alt2.MODE <> 3, alt2.COACH = 0),

? Step 3: Introduce conditions for categorical variables with more than two levels
if(alt1.FM_MODE_BUS = 1, alt1.FM_MODE_TAXI = 0), if(alt1.FM_MODE_TAXI = 1, alt1.FM_MODE_BUS = 0),
if(alt2.FM_MODE_BUS = 1, alt2.FM_MODE_TAXI = 0), if(alt2.FM_MODE_TAXI = 1, alt2.FM_MODE_BUS = 0)


;model:

U(alt1)  = b_mode.dummy[0|0]                  * MODE[1,3,2]

         + b_fm_mode_bus_rail[0]              * FM_MODE_BUS[0,1]                 * RAIL[0,1]
         + b_fm_mode_taxi_rail[0]             * FM_MODE_TAXI[0,1]                * RAIL[0,1]
         + b_fm_mode_bus_coach[0]             * FM_MODE_BUS[0,1]                 * COACH[0,1]
         + b_fm_mode_taxi_coach[0]            * FM_MODE_TAXI[0,1]                * COACH[0,1]

         + b_tt.dummy[0|0]                    * TT[2,3,1]
         + b_cost.dummy[0|0|0|0]              * COST[2,3,4,5,1]
         /

U(alt2)  = b_mode.dummy                       * MODE

         + b_fm_mode_bus_rail                 * FM_MODE_BUS                      * RAIL
         + b_fm_mode_taxi_rail                * FM_MODE_TAXI                     * RAIL
         + b_fm_mode_bus_coach                * FM_MODE_BUS                      * COACH
         + b_fm_mode_taxi_coach               * FM_MODE_TAXI                     * COACH

         + b_tt.dummy                         * TT
         + b_cost.dummy                       * COST

$


Now, the design with 60 rows, optimized with the default swapping algorithm, has following properties:
- mode levels 1,2,3 (rail,car,coach) and other attributes that are not alternative-specific variables (tt, cost) appear 20 times each in both alt1 and alt2, so perfect balance
- fm_mode_bus and fm_mode_taxi are also balanced (20 times fm_mode_bus=1, 20 times fm_mode_taxi=1, and 20 times when both = 0, which is level 3 walk (base). The thing is that they are balanced over the entire design with 60 rows. And they are relevant only when mode=1 OR 3 (rail or coach), so the level balance of these attributes should be maintained within these 40 rows when mode=1 OR 3. In current design, I have appearances of fm_mode_bus=1 when mode=2 (car), which is clearly not what I want.

What I want is shown in a spreadsheet here: https://docs.google.com/spreadsheets/d/1GPTXcokjkwcordQq_N1lB4HT1bLcXf-g/edit?usp=sharing&ouid=100486506683057714552&rtpof=true&sd=true

How can I achieve that in Ngene?

I thought that it would help when I add an additional condition:
if(alt1.MODE = 2, alt1.FM_MODE_BUS = 0 AND alt1.FM_MODE_TAXI = 0)
and manually specify the attribute level count constraints for bus on first mile so that FM_MODE_BUS=1 about one third (10-16) of the times when MODE is rail or coach (40 out of 60 rows).
+ b_fm_mode_bus_rail[0] * FM_MODE_BUS[0,1](44-50,10-16) * RAIL[0,1]
+ b_fm_mode_bus_coach[0] * FM_MODE_BUS[0,1](44-50,10-16) * COACH[0,1]

But a design with an if() condition like above results in no balance in the MODE attribute.

Can I maintain level balance of generic attributes (mode, tt, cost) over 60 rows, and at the same time maintain level balance of attributes that are turned on by indicators over the rows when they are actually active (turned on)?

Many thanks
Bartosz
bartoszbursa
 
Posts: 11
Joined: Tue Mar 18, 2025 9:29 pm

PreviousNext

Return to Support for Ngene Desktop (v1.x)

Who is online

Users browsing this forum: No registered users and 16 guests

cron