! The Product Family Design Problem,
! Given:
   1) a set of possible features to include in any product/design,
        each feature has an incremental cost.
   2) a set of market segments, each segment has:
       a demand volume,and
       a subset of the features that are needed by this segment.
We want to create a set of one or more designs.
Each design contains a subset of all possible features.
The cost per unit of a specific design is the
  sum of incremental cost of all features included in the design.
Each market segment will be assigned to the design with the
  lowest cost per unit that
  contains at least all the features needed by that segment.
The volume of a design is the
  sum of the demand volumes of all market segments assigned to the design.
We typically do not want to have more than two or three designs.
With a limited number of designs, we waste money on a segment
if the design assigned to that segment contains more features
than the segment requires.
We want to find the cheapest set of designs that satisfies all
the segment demands.

Example application:
  Choosing wire harness configurations(designs) for a family
of automobiles. Each automobile type has a forecast total demand
as well as a set of features needed in its wire harness,
e.g., power moon roof, heated seats, trailer power connector, etc. . 
We typically want to have fewer wire harness types than
automobile types. So which harness configurations should we choose,
so that for each automobile there is a least one wire harness
design that has all the required features?;

! Keywords: Assortment planning, Marketing, Wire harness design,
  Product design, Symmetry;
SETS:
  MSEG: VOLS;
  FEATURE: COSTI;
  DESIGN: VOLD, COSTD, COSTOT, XAXIS;
  MXF( MSEG, FEATURE);
  FXD( FEATURE, DESIGN): ZF, VCZ;
  PXD( MSEG, DESIGN): ZP;
ENDSETS
DATA: NDSGMX = 8; ! Maximum designs to try; DESIGN = 1..NDSGMX; ! Number of designs allowed; MSEG = S01 S02 S03 S04 S05 S06 S07 S08; ! The market segments...; VOLS = 55 75 88 63 24 18 43 15; ! and demand volumes; FEATURE= F01 F02 F03 F04 F05 F06 F07 F08 F09 F10 F11 F12; ! Incremental cost of per unit of each feature; ! 1 2 3 4 5 6 7 8 9 10 11 12; COSTI= 0.94 0.45 0.36 0.83 0.49 0.92 0.18 0.27 0.62 0.73 0.58 0.31; ! The features needed in each segment, specified as MSEG,feature pairs; MXF = S01 F01 S01 F03 S01 F05 S01 F10 S02 F02 S02 F03 S02 F04 S02 F11 S02 F12 S03 F01 S03 F04 S03 F05 S03 F09 S04 F04 S04 F05 S04 F07 S04 F10 S05 F01 S05 F02 S05 F06 S05 F08 S05 F09 S05 F10 S06 F03 S06 F06 S06 F07 S06 F09 S06 F10 S06 F11 S06 F12 S07 F02 S07 F04 S07 F05 S07 F06 S07 F11 S08 F02 S08 F06 S08 F08 S08 F09 S08 F10 S08 F11 S08 F12; ENDDATA SUBMODEL DESIGNIT: ! Variables: ZP(p,d) = 1 if segment p is satisfied by design d, ZF(f,d) = 1 if feature f is in design d; ! This model is OK for a modest number of bins/designs, e.g., 3. For larger problems, a 'column generation' approach may be better; ! Minimize the cost of all designs run; MIN = OBJ; OBJ= @SUM( DESIGN(d) | d #LE# NDTRY: COSTD(d)); ! Each segment must be assigned to one design or harness type; @FOR( MSEG(p): @SUM( PXD(p, d) | d #LE# NDTRY: ZP(p,d)) = 1; ); ! Must make enough of each design to satisfy demands of all segmentes assigned to that design; @FOR( DESIGN(d) | d #LE# NDTRY: VOLD(d) = @SUM( MSEG(p): VOLS(p)*ZP(p,d)); ); ! Feature f must be in design d if there is a segment p assigned to design d that needs feature f; @FOR( FXD(f,d) | d #LE# NDTRY: @BIN( ZF(f,d)); @FOR( MXF(p,f): ZF( f,d) >= ZP(p,d); ); ); ! The total cost of each design is; @FOR( DESIGN(d) | d #LE# NDTRY: ! Linearize the following expression; ! COSTD(d) = VOLD( d)* @SUM(FXD(f,d): COSTI(f)*ZF(f,d)); @FOR( FXD(f,d): ! If feature f is in design d, then that contributes cost COSTI(f)*VOLD(d); VCZ(f,d) >= COSTI(f)*( VOLD(d) - (1-ZF(f,d))*@SUM( MSEG(p): VOLS(p))); ); COSTD(d) = @SUM( FXD(f,d): VCZ(f,d)); ! Optional lower bound on the cost; COSTD(d) >= @SUM( MSEG( p): VOLS(p)*@SUM( MXF(p,f): COSTI(f))*ZP(p,d)); ); ! We may optionally want to add some symmetry elimination constraints.; ! Basic idea: if bins are equivalent, then we can order the bins by the smallest index that appears in each bin. Thus, if item p is in bin d, then some item i < p must be in bin d-1; @FOR( PXD(p,d) | d #GT# 1 #AND# d #LE# NDTRY: ZP(p,d) <= @SUM( PXD( i, d1) | i #LT# p #AND# d1 #EQ# d-1: ZP( i, d1)) ); ENDSUBMODEL
CALC: @SET('TERSEO',3); ! Output level (0:verb,1:terse,2:errors,3:none); @FOR( DESIGN(k): ! Loop over all possible number of designs; NDTRY = k; ! Number of designs to try; @SOLVE( DESIGNIT); @WRITE(@NEWLINE(2),' Case: Best ',k,' product design.',@NEWLINE(1)); @WRITE(' De- Vol- Unit ',@NEWLINE(1)); @WRITE(' sign: ume cost Contains features',@NEWLINE(1)); @FOR( DESIGN( d) | d #LE# NDTRY: UCOST = @SUM(FXD(f,d): COSTI(f)*ZF(f,d)); @WRITE( ' ',DESIGN(d),': ', @FORMAT(VOLD(d),'6.0f'), @FORMAT(UCOST,'7.2f'),' '); @FOR( FXD(f,d) : @IFC( ZF(f,d) #GT# 0.5: @WRITE(' ',FEATURE(f)); @ELSE @WRITE(' '); ); ); @WRITE( @NEWLINE(1)); ); @WRITE(' Tot. cost= ',@FORMAT( OBJ,'6.2f'),@NEWLINE(1)); COSTOT( k) = OBJ; ! Save the costs for graph/charting later; XAXIS( k) = k; ! Record for later chart; @WRITE(@NEWLINE(1), ' Assigned-to', @NEWLINE(1), ' MSeg design Requires features ',@NEWLINE(1)); @FOR( MSEG(p): @WRITE( ' ',MSEG(p),': '); @FOR( PXD(p,d) | d #LE# NDTRY #AND# ZP(p,d) #GT# 0.5: @WRITE( ' ', DESIGN(d),' '); ); @FOR( FEATURE(f): @IFC( @IN( MXF, p, f): @WRITE(' ', FEATURE(f)); @ELSE @WRITE(' ') ); ); @WRITE( @NEWLINE(1)); ); ); ! Generate a tradeoff curve; @CHARTSCATTER( 'Cost vs Product Variety', !Title; 'Number products (designs)',! X-axis label; 'Total Variable Production Cost', ! Y-axis label; 'Cost curve', ! Label of curve; xaxis, ! X-axis values; costot); ! Y-axis values; ! If you like to connect the dots...; @CHARTCURVE( 'Cost vs Product Variety', !Title; 'Number products (designs)',! X-axis label; 'Total Variable Production Cost', ! Y-axis label; 'Cost curve', ! Label of curve; xaxis, ! X-axis values; costot); !Y-axis values; ENDCALC