home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / HOPFIELD.ZIP / HOPFIELD.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-07-27  |  10.5 KB  |  350 lines

  1. {$R+}
  2. PROGRAM traveling_salesperson ;
  3.  
  4. (* Copyright 1987 - Knowledge Garden Inc.
  5.                     473A Malden Bridge Rd.
  6.                     R.D. 2
  7.                     Nassau, NY 12123       *)
  8.  
  9.  
  10. (* TSP solves a series of differential equations which simulate a neural
  11.    net solution of the traveling salesperson problem. The problem and
  12.    the equations are described in the article "Computing with Neurons" in
  13.    the July 1987 issue of AI Expert Magazine.
  14.  
  15.    This program has been tested using Turbo ver 3.01A on an IBM PC/AT. It has
  16.    been run under both DOS 3.2 and Concurrent 5.0 .
  17.  
  18.    We would be pleased to hear your comments, good or bad, or any applications
  19.    and modifications of the program. Contact us at:
  20.  
  21.      AI Expert
  22.      500 Howard St.
  23.      San Francisco, CA 94105
  24.  
  25.    Bill and Bev Thompson    *)
  26.  
  27. (* Uses Turbo3, CRT; *)  (* To compile with later versions of Turbo Pascal *)
  28.  
  29.  CONST
  30.   max_city = 'E' ;         (* max_city and max_position are the size of the *)
  31.   max_position = 5 ;       (* neural net. They must match. Cities run from *)
  32.                            (* A to max_city *)
  33.  
  34.   a = 500.0 ;              (* these are the weighting constants described *)
  35.   b = 500.0 ;              (* in the article. By changing then you can *)
  36.   c = 200.0 ;              (* get different types of solutions *)
  37.   d = 300.0 ;              (* d seems to have the most effect, increasing *)
  38.                            (* it produces shorter distance routes, but *)
  39.                            (* they aren't necessarily real tours. *)
  40.  
  41.   u0 = 0.02 ;              (* This parameter effects the output voltage of *)
  42.                            (* the amplifiers. Increasing it gives a broader *)
  43.                            (* curve. *)
  44.  
  45.   n = 7 ;                  (* This term affects global inhibition of the *)
  46.                            (* network. By setting it slightly larger than *)
  47.                            (* the number of cities, we seem to get better *)
  48.                            (* results *)
  49.  
  50.   h = 0.01 ;               (* The time step *)
  51.  
  52.  TYPE
  53.   cities = 'A' .. max_city ;
  54.   positions = 1 .. max_position ;
  55.  
  56.  
  57.  VAR
  58.   u : ARRAY [cities,positions] OF real ;      (* Input voltages *)
  59.   dist : ARRAY [cities,cities] OF real ;      (* Distances between cities *)
  60.  
  61.  
  62.  
  63.  FUNCTION v(city : cities ; position : positions) : real ;
  64.   (* This function calculates the output voltage from an amplifier
  65.      tanh calculates the hyperbolic tangent which gives the shape
  66.      of the output curve described in the article *)
  67.  
  68.   FUNCTION tanh(r : real) : real ;
  69.    VAR
  70.     r1,r2 : real ;
  71.    BEGIN
  72.     IF r > 20.0
  73.      THEN tanh := 1.0
  74.     ELSE IF r < -20.0
  75.      THEN tanh := -1.0
  76.     ELSE
  77.      BEGIN
  78.       r1 := exp(r) ;
  79.       r2 := exp(-r) ;
  80.       tanh := (r1 - r2) / (r1 + r2) ;
  81.      END ;
  82.    END ; (* tanh *)
  83.  
  84.   BEGIN
  85.    v := (1.0 + tanh(u[city,position] / u0)) / 2.0 ;
  86.   END ; (* v *)
  87.  
  88.  
  89.  FUNCTION f(city : cities ; position : positions) : real ;
  90.   (* This function calculates the right hand side of the differential
  91.      equations described in the article. It is not optimized for anything
  92.      and is pretty slow. *)
  93.  
  94.   FUNCTION col_sum(cty : cities) : real ;
  95.    (* column inhibition. This function helps keep the number of
  96.       output items in each column small *)
  97.    VAR
  98.     col : positions ;
  99.     sum : real ;
  100.    BEGIN
  101.     sum := 0.0 ;
  102.     FOR col := 1 TO max_position DO
  103.      IF col <> position
  104.       THEN sum := sum + v(cty,col) ;
  105.     col_sum := sum ;
  106.    END ; (* col_sum *)
  107.  
  108.   FUNCTION row_sum(p : positions) : real ;
  109.    (* row inhibition. This function helps keep the number of
  110.       output items in each row small *)
  111.    VAR
  112.     row : cities ;
  113.     sum : real ;
  114.    BEGIN
  115.     sum := 0.0 ;
  116.     FOR row := 'A' TO max_city DO
  117.      IF row <> city
  118.       THEN sum := sum + v(row,p) ;
  119.     row_sum := sum ;
  120.    END ; (* row_sum *)
  121.  
  122.   FUNCTION matrix_sum : real ;
  123.    (* global inhibition. This function keeps the total number of cities
  124.       visited small *)
  125.    VAR
  126.     row : cities ;
  127.     col : positions ;
  128.     sum : real ;
  129.    BEGIN
  130.     sum := 0.0 ;
  131.     FOR row := 'A' TO max_city DO
  132.      FOR col := 1 TO max_position DO
  133.       sum := sum + v(row,col) ;
  134.     matrix_sum := sum ;
  135.    END ; (* matrix_sum *)
  136.  
  137.   FUNCTION dist_sum : real ;
  138.    (* distance inhibition. The inhibition is larger for longer tours.
  139.       Note that neuron (X,max_position) is connected to neuron (X,1),
  140.       in other words, the net is circular *)
  141.    VAR
  142.     c : cities ;
  143.     sum : real ;
  144.    BEGIN
  145.     sum := 0.0 ;
  146.     IF position = max_position
  147.      THEN
  148.       FOR c := 'A' TO max_city DO
  149.        sum := sum + dist[city,c] * (v(c,1) + v(c,position - 1))
  150.     ELSE IF position = 1
  151.      THEN
  152.       FOR c := 'A' TO max_city DO
  153.        sum := sum + dist[city,c] * (v(c,position + 1) + v(c,max_position))
  154.     ELSE
  155.      FOR c := 'A' TO max_city DO
  156.       sum := sum + dist[city,c] * (v(c,position + 1) + v(c,position - 1)) ;
  157.     dist_sum := sum ;
  158.    END ; (* dist_sum *)
  159.  
  160.   BEGIN
  161.    f := -u[city,position] - a * col_sum(city) - b * row_sum(position)
  162.         - c * (matrix_sum - n) - d * dist_sum ;
  163.   END ; (* f *)
  164.  
  165.  
  166.  PROCEDURE iterate ;
  167.   (* The basic solution process. This is a terrible way to solve differential
  168.      equations. Don't use it for anything serious, it performs poorly
  169.      when the number of cities gets larger than 7 or 8.
  170.      We keep iterating until the norm is less than tol or until the user
  171.      gets bored and presses the space bar. *)
  172.   CONST
  173.    tol = 1.0E-05 ;
  174.   VAR
  175.    step : integer ;
  176.    c1 : cities ;
  177.    i : positions ;
  178.    nr : real ;
  179.    u_old : ARRAY [cities,positions] OF real ;
  180.    ch : char ;
  181.  
  182.   FUNCTION norm : real ;
  183.    (* The norm is a measure of how much change there has been between
  184.       solutions. This is an infinity norm, calculated as the maximum
  185.       absolute value of the difference between components of the
  186.       solution vectors. We calculate the relative norm as:
  187.         N(u_new - u) / N(u). *)
  188.    VAR
  189.     cx : cities ;
  190.     ix : positions ;
  191.     max,max_comp : real ;
  192.    BEGIN
  193.     max := 0.0 ;
  194.     FOR cx := 'A' TO max_city DO
  195.      FOR ix := 1 TO max_position DO
  196.       BEGIN
  197.        IF abs(u_old[cx,ix] - u[cx,ix]) > max
  198.         THEN max := abs(u_old[cx,ix] - u[cx,ix]) ;
  199.        IF abs(u[cx,ix]) > max_comp
  200.         THEN max_comp := abs(u[cx,ix]) ;
  201.       END ;
  202.     norm := max / max_comp ;
  203.    END ; (* norm *)
  204.  
  205.   PROCEDURE print_matrix ;
  206.    (* Every so often, we print the input and output matrices so that
  207.       you can see what is going on. If the output matrix describes a
  208.       valid tour, we print that also. *)
  209.    VAR
  210.     c1 : cities ;
  211.     i : positions ;
  212.     vv : real ;
  213.     t : ARRAY [1 .. max_position] OF char ;
  214.     t_count : integer ;
  215.  
  216.    PROCEDURE write_tour ;
  217.     VAR
  218.      i : positions ;
  219.      t_dist : real ;
  220.     BEGIN
  221.      t_dist := 0.0 ;
  222.      FOR i := 1 TO max_position - 1 DO
  223.       t_dist := t_dist + dist[t[i],t[i+1]] ;
  224.      t_dist := t_dist + dist[t[max_position],t[1]] ;
  225.      write(output,'Tour: ') ;
  226.      FOR i := 1 TO max_position DO
  227.       write(output,t[i]) ;
  228.      writeln(output,'   dist = ',t_dist) ;
  229.     END ; (* write_tour *)
  230.  
  231.    PROCEDURE matrix_heading ;
  232.     VAR
  233.      i : positions ;
  234.     BEGIN
  235.      write(output,'  ') ;
  236.      FOR i := 1 TO max_position DO
  237.       write(output,i : 12) ;
  238.      writeln ;
  239.     END ; (* matrix_heading *)
  240.  
  241.    BEGIN
  242.     t_count := 0 ;
  243.     FOR i := 1 TO max_position DO
  244.      t[i] := chr(0) ;
  245.     writeln(output) ;
  246.     writeln(output,'Step: ',step,' norm = ',nr) ;
  247.     writeln(output) ;
  248.     writeln(output,'Input Voltages') ;
  249.     matrix_heading ;
  250.     FOR c1 := 'A' TO max_city DO
  251.      BEGIN
  252.       write(output,c1,'    ') ;
  253.       FOR i := 1 TO max_position DO
  254.        write(output,u[c1,i] : 12 : 5) ;
  255.       writeln(output) ;
  256.      END ;
  257.     writeln(output) ;
  258.     writeln(output,'Output Voltages') ;
  259.     matrix_heading ;
  260.     FOR c1 := 'A' TO max_city DO
  261.      BEGIN
  262.       write(output,c1,'    ') ;
  263.       FOR i := 1 TO max_position DO
  264.        BEGIN
  265.         vv := v(c1,i) ;
  266.         write(output,vv : 12 : 5) ;
  267.         IF (vv > 0.8) AND (t_count < max_position) AND (t[i] = chr(0))
  268.          THEN
  269.           BEGIN
  270.            t_count := t_count + 1 ;
  271.            t[i] := c1 ;
  272.           END ;
  273.        END ;
  274.       writeln(output) ;
  275.      END ;
  276.     IF t_count = max_position
  277.      THEN write_tour ;
  278.    END ; (* print_matrix *)
  279.  
  280.   BEGIN
  281.    step := 0 ;
  282.    REPEAT
  283.     step := step + 1 ;
  284.     move(u,u_old,sizeof(u)) ;
  285.     FOR c1 := 'A' TO max_city DO
  286.      FOR i := 1 TO max_position DO
  287.       u[c1,i] := u[c1,i] + h * f(c1,i) ;
  288.     nr := norm ;
  289.     IF ((step MOD 10) = 0) OR (step < 10)
  290.      THEN print_matrix ;
  291.    UNTIL keypressed OR (nr < tol) ;
  292.    IF keypressed
  293.     THEN read(kbd,ch) ;
  294.    print_matrix ;
  295.   END ; (* iterate *)
  296.  
  297.  
  298.  PROCEDURE initialize ;
  299.   TYPE
  300.    location = RECORD
  301.                x : real ;
  302.                y : real ;
  303.               END ;
  304.    city_array = ARRAY [cities] OF location ;
  305.   CONST
  306.    u00 = -0.01386 ;
  307. (* city_loc : city_array = ( (x : 0.21192 ; y : 0.54866),
  308.                              (x : 0.98817 ; y : 0.68465),
  309.                              (x : 0.53109 ; y : 0.72173),
  310.                              (x : 0.31459 ; y : 0.79397),
  311.                              (x : 0.63290 ; y : 0.85573)) ;
  312.  
  313.    These are the values we used for the article, if you want to
  314.    check our results, remove the comments here and use this data *)
  315.   VAR
  316.    c1,c2 : cities ;
  317.    i : positions ;
  318.    city_loc : city_array ;
  319.    ch : char ;
  320.   BEGIN
  321.    randomize ;
  322.    FOR c1 := 'A' TO max_city DO
  323.     BEGIN
  324.      city_loc[c1].x := random ;
  325.      city_loc[c1].y := random ;
  326.     END ;
  327.     FOR c1 := 'A' TO pred(max_city) DO
  328.     BEGIN
  329.      dist[c1,c1] := 0.0 ;
  330.      FOR c2 := succ(c1) TO max_city DO
  331.       BEGIN
  332.        dist[c1,c2] := sqrt(sqr(city_loc[c1].x - city_loc[c2].x) +
  333.                            sqr(city_loc[c1].y - city_loc[c2].y)) ;
  334.        dist[c2,c1] := dist[c1,c2] ;
  335.       END ;
  336.     END ;
  337.    dist[max_city,max_city] := 0.0 ;
  338.    FOR c1 := 'A' TO max_city DO
  339.     FOR i := 1 TO max_position DO
  340.      u[c1,i] := u00 + (((2 * random - 1.0) / 10.0) * u0) ;
  341.    clrscr ;
  342.    writeln('TSP         [c] 1987 Knowledge Garden Inc.') ;
  343.    writeln('                     473A Malden Bridge Rd') ;
  344.    writeln('                     Nassau, NY 12123') ;
  345.    writeln ;
  346.    writeln('Press <Space Bar> to begin - Press again to stop iterating.') ;
  347.    read(kbd,ch) ;
  348.   END ; (* initialize *)
  349.  
  350.  
  351.  BEGIN
  352.   initialize ;
  353.   iterate ;
  354.  END.
  355.