1      subroutine linfs(n, x, y, beta1, beta2, lambda, kount, p, q, r,
2     1                 ifault)
3c
4c-----------------------------------------------------------------------
5c
6c   Package:  SLRPACK
7c
8c   Version:  October, 1985
9c
10c-----------------------------------------------------------------------
11c
12c   PURPOSE
13c   -------
14c
15c   This user-callable subroutine solves the simple model,
16c   y = beta1 + (beta2)x, under the Chebychev norm criterion.
17c
18c   DESCRIPTION
19c   -----------
20c
21c   1.  The Y's are observed values of the dependent variable and the
22c       X's are the observed values of the independent variables, the
23c       predictor variables.
24c
25c   2.  The general Chebychev problem is to minimize LAMBDA where
26c
27c            LAMBDA = MAX( |Y(i) - BETA1 - X(i)*BETA2| )  over all i
28c
29c       such that
30c
31c            Y(i)-LAMBDA <= BETA1 + X(i)*BETA2 <= Y(i)+LAMBDA
32c
33c   3.  The optimal value of (BETA1, BETA2)' will minimize the
34c       maximum deviation and LAMBDA will be the value of this deviation
35c
36c   INPUT PARAMETERS
37c   ----------------
38c
39c   N      Integer scalar (unchanged on output).
40c          Number of observations.
41c
42c          N must be at least 3.
43c
44c   X      Real vector dimensioned at least N (unchanged on output).
45c          Observed values of the independent variable.
46c
47c   Y      Real vector dimensioned at least N (unchanged on output).
48c          Observed values of the dependent variable.
49c
50c   OUTPUT PARAMETERS
51c   -----------------
52c
53c   BETA1      Real scalar.
54c              The estimated intercept term for the fitted line.
55c
56c   BETA2      Real scalar.
57c              The estimated slope term for the fitted line.
58c
59c   LAMBDA     Real scalar.
60c              The least maximum absolute deviation, also
61c              the objective function value.
62c
63c   P          Integer scalar.
64c              Indicates which row of X is the p-th constraint.
65c
66c   Q          Integer scalar.
67c              Indicates which row of X is the q-th constraint.
68c
69c   R          Integer scalar.
70c              Indicates which row of X is the r-th constraint.
71c
72c   KOUNT      Integer scalar.
73c              The number of iterations.
74c
75c   IFAULT     Integer scalar.
76c              Failure indicator.
77c
78c              = 0    normal termination
79c
80c              = 1    the data set is too small
81c                     cannot compute BETA1, BETA2, LAMBDA, P, Q, R
82c
83c              = 2    all x values are equal
84c                     cannot compute BETA1, BETA2, LAMBDA, P, Q, R
85c
86c              = 3    the data are collinear, all constraints are feasib
87c                     cannot compute P, Q, R
88c
89c   PRECISION
90c   ---------
91c
92c   All calculations are done in single precision.
93c
94c   LANGUAGE
95c   --------
96c
97c   All code is written in standard Fortran 77.
98c
99c   OTHER SUBROUTINES
100c   -----------------
101c
102c   PORT  subroutine  R1MACH
103c
104c   REFERENCE
105c   ---------
106c
107c   Sklar, M. and R. Armstrong (1983). "A Linear Programming Algorithm
108c        for the Simple Model for Discrete Chebychev Curve Fitting",
109c        Computers and Operations Research 10, 237-248.
110c
111c   Sklar, M. and R. Armstrong (1984). "An Algorithm for Discrete
112c      Chebychev Curve Fitting for the Simple Model Using A Dual
113c      Linear Programming Approach", Communications in Statistics:
114c      Simulation and Computation, 13(4), 555-569.
115c
116c   AUTHORS
117c   -------
118c
119c   Michael G. Sklar and Ronald D. Armstrong
120c   University of Georgia
121c
122c   NBS CONTACT
123c   -----------
124c
125c   Sally E. Howe
126c   Scientific Computing Division
127c   Center for Applied Mathematics
128c   National Engineering Labratory
129c   301-921-3395
130c
131c---------------------------------------------------------------------
132c
133      integer           ifault,irow,isave,kount,n
134      integer           p,q,r,s
135c
136      real              acu,alpha1,alpha2,beta1,beta2,big,d,delhat
137      real              delstr,devsgn,div,dsubi,dsubr,dsubs,lambda
138      real              ratio,r1,r2,save,signp,signq,signr
139      real              signs,s1,s2,sumr,sums,top
140      real              x(*), y(*)
141c
142c---------------------
143c   internal variables
144c---------------------
145c
146c   signp, signq, signr, signs  Indicators for the p-th, q-th, r-th,
147c                               and s-th constraints, respectively.
148c
149c   sign(k)  =  1  If the k-th constraint is at or violates its
150c                  upper bound.
151c            = -1  If it is at or violates its lower bound.
152c
153c   dsubi   Amount by which the i-th constraint is violated.
154c
155c   dsubr   Amount by which the r-th constraint is violated.
156c
157c   dsubs   Amount by which the s-th constraint is violated.
158c
159c   delhat  The smallest delta necessary to bring constraints into
160c           feasibility.
161c
162c   delstr  The largest tolerable delta allowed before a feasible
163c           constraint moves beyond its opposite bound.
164c
165c   devsgn  The signed amount violated in the s-th constraint.
166c
167c   alpha1, alpha2  Y-coordinates of p-th and q-th constraints.
168c
169c   acu     Machine-dependent constant which is used to test for zero.
170c           ACU is set to 100 times the relative machine accuracy.
171c
172c   big     Machine-dependent constant which is used in determining the
173c           minimum ratio.  BIG is set to the largest floating point
174c           number available.
175c
176      kount=0
177      beta1=0.0
178      beta2=0.0
179      lambda=0.0
180      p=0
181      q=0
182      r=0
183c
184c   check problem size
185c
186      if (n .le. 2) then
187         ifault = 1
188         return
189      endif
190      acu = r1mach(4) * 100.0
191      big = r1mach(2)
192      ifault=0
193c
194c     get p-th and q-th constraints and
195c     check that not all x-values are equal
196c
197      p=1
198      do 110 i=2,n
199          if(abs(x(p)-x(i)).gt.acu)goto 120
200  110 continue
201c
202      ifault=2
203      p = 0
204      return
205c
206  120 q=i
207c
208c     step 1 - compute initial (trivial) solution
209c
210      s=0
211      d=1./(x(q)-x(p))
212      alpha1=y(p)
213      alpha2=y(q)
214      beta1=d*(x(q)*alpha1-x(p)*alpha2)
215      beta2=d*(alpha2-alpha1)
216c
217c     step 2 - add a constraint (labeled r-th) to the problem
218c
219      irow=p
220  130 if(irow.eq.n) then
221         ifault=3
222         p=0
223         q=0
224         return
225      endif
226      irow=irow+1
227c
228c     check if r-th constraint is feasible
229c     (i.e. if p-th, q-th, and r-th constraints are not collinear)
230c
231      dsubr=beta1+x(irow)*beta2-y(irow)
232      if(abs(dsubr).lt.acu)goto 130
233      signr=sign(1.,dsubr)
234      ifault=0
235      r=irow
236c
237c     adjust for the r-th constraint
238c
239      r1=d*(x(q)-x(r))
240      r2=d*(x(r)-x(p))
241      signp=sign(1.,-signr*r1)
242      signq=sign(1.,-signr*r2)
243      sumr=signr-signp*r1-signq*r2
244      lambda=abs(dsubr/sumr)
245      alpha1=y(p)+signp*lambda
246      alpha2=y(q)+signq*lambda
247      beta1=d*(x(q)*alpha1-x(p)*alpha2)
248      beta2=d*(alpha2-alpha1)
249c
250c     step 3 - find a fourth constraint (labeled s-th) which most
251c              violates the current solution
252c
253  140 s=0
254      dsubs=acu
255      do 150 i=1,n
256          dsubi=abs(beta1+beta2*x(i)-y(i))-lambda
257          if(dsubi.le.dsubs) go to 150
258          dsubs=dsubi
259          s=i
260  150 continue
261c
262c     check for termination - no constraints are violated
263c
264      if(s.eq.0) go to 240
265c
266c     compute characteristics of most-violated (s-th) constraint
267c
268      devsgn=beta1+beta2*x(s)-y(s)
269      signs=sign(1.,devsgn)
270      s1=d*(x(q)-x(s))
271      s2=d*(x(s)-x(p))
272      sums=-signs+signq*s2 +signp*s1
273c
274c     step 4 - determine which constraint will not be binding
275c              when the s-th constraint is made feasible (by
276c              locating the minimum ratio)
277c
278  160 ratio=big
279c
280c     if the signs are not the same, the p-th constraint is not a
281c     candidate
282c
283      if(signs*sign(1.,s1).ne.signp)goto 170
284c
285c     ignore ratio if denominator is effectively zero
286c
287      if(abs(s1).lt.acu)goto 170
288      ratio=abs(r1/s1)
289c
290c     if the signs are not the same, the q-th constraint is not a
291c     candidate
292c
293  170 if(signs*sign(1.,s2).ne.signq)goto 180
294c
295c     ignore ratio if denominator is effectively zero
296c
297      if(abs(s2).lt.acu)goto 180
298c
299c     if minimum is p-th, go to process p-th
300c
301      if(abs(r2/s2).lt.ratio)goto 200
302      go to 210
303c
304c     if minimum is q-th, go to switch the p-th and q-th constraints so
305c     that the algorithm will always process the p-th constraint
306c
307  180 if(ratio.lt.big)goto 210
308c
309c     step 5 - no minimum was located, so process the r-th constraint
310c
311      delhat=abs(dsubs/sums)
312c
313c     calculate the largest tolerable delta
314c
315      div=abs(sumr)-2.
316      if(div.lt.acu) go to 190
317      delstr=2.*lambda/div
318      if(delstr.ge.delhat) go to 190
319c
320c     step 5a - as the s-th becomes feasible, the r-th becomes
321c               infeasible by moving outside a bound, so switch
322c               r-th and s-th constraint indicators
323c
324      save=sums
325      sums=-sumr+signr+signr
326      sumr=-save
327      save=signr
328      signr=signs
329      signs=-save
330      dsubs=abs(sums*delhat) -2.*lambda
331      lambda=lambda+delhat
332      alpha1=y(p)+signp*lambda
333      alpha2=y(q)+signq*lambda
334      beta1=d*(x(q)*alpha1-x(p)*alpha2)
335      beta2=d*(alpha2-alpha1)
336      save=r1
337      r1=s1
338      s1=save
339      save=r2
340      r2=s2
341      s2=save
342      isave=r
343      r=s
344      s=isave
345      go to 160
346c
347c     step 5b - replace the r-th constraint with the s-th constraint,
348c               since the s-th became feasible and the r-th moved
349c               interior (between bounds)
350c
351  190 signr=signs
352      r1=s1
353      r2=s2
354      sumr=-sums
355      r=s
356      go to 230
357c
358c     step 6 - for efficiency, the algorithm always processes the
359c              p-th constraint.  if the q-th is to be processed,
360c              switch p-th and q-th constraints
361c
362  200 isave=p
363      p=q
364      q=isave
365      save=signp
366      signp=signq
367      signq=save
368      save=alpha1
369      alpha1=alpha2
370      alpha2=save
371      save=r1
372      r1=r2
373      r2=save
374      save=s1
375      s1=s2
376      s2=save
377c
378c     step 7 - process the movement of the p-th constraint
379c
380  210 delhat=abs(r1*dsubs/(r1*sums+s1*sumr))
381      top=-2.*lambda*r1
382      div=r1 +r1 +signp*sumr
383      if(sign(1.,top).ne.sign(1.,div)) go to 220
384      if(abs(div).lt.acu) go to 220
385      delstr=top/div
386c
387c     check to see if p-th constraint swings across to its
388c     opposite bound
389c
390      if(delstr.ge.delhat) go to 220
391c
392c     step 7a - the p-th constraint moves to its opposite bound,
393c               and the s-th constraint is still infeasible.
394c               adjust for the movement, then go to step 4 to
395c               locate the next smallest ratio
396c
397      lambda=lambda+delstr
398      dsubs=dsubs-delstr*abs(sums+s1*sumr/r1)
399      sumr=sumr+2.*signp*r1
400      sums=sums-2.*signp*s1
401      signp=-signp
402      alpha1=y(p)+signp*lambda
403      alpha2=y(q)+signq*lambda
404      go to 160
405c
406c     step 7b - the s-th became feasible and the p-th moved interior
407c               so replace the p-th constraint with the s-th constraint
408c
409  220 signp=signs
410      r1=r1/s1
411      r2=r2-s2*r1
412      sumr=signr-signp*r1-signq*r2
413      p=s
414      kount=kount+1
415c
416c     update lambda, compute the new solution - goto step 3 to
417c     locate a new most-violated constraint
418c
419  230 s=0
420      lambda=lambda+delhat
421      alpha1=y(p)+signp*lambda
422      alpha2=y(q)+signq*lambda
423      d=1./(x(q)-x(p))
424      beta1=d*(x(q)*alpha1-x(p)*alpha2)
425      beta2=d*(alpha2-alpha1)
426      go to 140
427  240 continue
428      return
429      end
430