subroutine ccs_mv ( m, n, ncc, icc, ccc, acc, x, b ) !*****************************************************************************80 ! !! ccs_mv() multiplies a CCS matrix by a vector ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 13 July 2014 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Iain Duff, Roger Grimes, John Lewis, ! User's Guide for the Harwell-Boeing Sparse Matrix Collection, ! October 1992 ! ! Parameters: ! ! Input, integer M, the number of rows. ! ! Input, integer N, the number of columns. ! ! Input, integer NCC, the number of CCS values. ! ! Input, integer ICC(NCC), the CCS rows. ! ! Input, integer CCC(N+1), the compressed CCS columns ! ! Input, real ( kind = rk ) ACC(NCC), the CCS values. ! ! Input, real ( kind = rk ) X(N), the vector to be multiplied. ! ! Output, real ( kind = rk ) B(M), the product A*X. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer m integer n integer ncc real ( kind = rk ) acc(ncc) real ( kind = rk ) b(m) integer ccc(n+1) integer i integer icc(ncc) integer j integer k real ( kind = rk ) x(n) b(1:m) = 0.0D+00 do j = 1, n do k = ccc(j), ccc(j+1) - 1 i = icc(k) b(i) = b(i) + acc(k) * x(j) end do end do return end subroutine ccs_print ( m, n, ncc, icc, ccc, acc, title ) !*****************************************************************************80 ! !! ccs_print prints a sparse matrix in CCS format. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer M, the number of rows in the matrix. ! ! Input, integer N, the number of columns in the matrix. ! ! Input, integer NCC, the number of CCS elements. ! ! Input, integer ICC(NCC), the CCS rows. ! ! Input, integer CCC(N+1), the compressed CCS columns. ! ! Input, real ( kind = rk ) ACC(NCC), the CCS values. ! ! Input, character ( len = * ) TITLE, a title. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer ncc real ( kind = rk ) acc(ncc) integer ccc(n+1) integer i integer icc(ncc) integer j integer k integer m character ( len = * ) title call i4_fake_use ( m ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) write ( *, '(a)' ) ' # I J A' write ( *, '(a)' ) ' ---- ---- ---- ----------------' write ( *, '(a)' ) ' ' if ( ccc(1) == 0 ) then j = 0 do k = 1, ncc i = icc(k) do while ( ccc(j+2) <= k - 1 ) j = j + 1 end do write ( *, '(2x,i4,2x,i4,2x,i4,2x,g16.8)' ) k - 1, i, j, acc(k) end do else j = 1 do k = 1, ncc i = icc(k) do while ( ccc(j+1) <= k ) j = j + 1 end do write ( *, '(2x,i4,2x,i4,2x,i4,2x,g16.8)' ) k, i, j, acc(k) end do end if return end subroutine get_unit ( iunit ) !*****************************************************************************80 ! !! GET_UNIT returns a free FORTRAN unit number. ! ! Discussion: ! ! A "free" FORTRAN unit number is a value between 1 and 99 which ! is not currently associated with an I/O device. A free FORTRAN unit ! number is needed in order to open a file with the OPEN command. ! ! If IUNIT = 0, then no free FORTRAN unit could be found, although ! all 99 units were checked (except for units 5, 6 and 9, which ! are commonly reserved for console I/O). ! ! Otherwise, IUNIT is a value between 1 and 99, representing a ! free FORTRAN unit. Note that GET_UNIT assumes that units 5 and 6 ! are special, and will never return those values. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 September 2005 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Output, integer IUNIT, the free unit number. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer i integer ios integer iunit logical lopen iunit = 0 do i = 1, 99 if ( i /= 5 .and. i /= 6 .and. i /= 9 ) then inquire ( unit = i, opened = lopen, iostat = ios ) if ( ios == 0 ) then if ( .not. lopen ) then iunit = i return end if end if end if end do return end subroutine i4_fake_use ( n ) !*****************************************************************************80 ! !! i4_fake_use() pretends to use a variable. ! ! Discussion: ! ! Some compilers will issue a warning if a variable is unused. ! Sometimes there's a good reason to include a variable in a program, ! but not to use it. Calling this function with that variable as ! the argument will shut the compiler up. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 April 2020 ! ! Author: ! ! John Burkardt ! ! Input: ! ! integer N, the variable to be "used". ! implicit none integer n if ( n /= n ) then write ( *, '(a)' ) ' i4_fake_use: variable is NAN.' end if return end subroutine i4vec_copy ( n, a1, a2 ) !*****************************************************************************80 ! !! I4VEC_COPY copies an I4VEC. ! ! Discussion: ! ! An I4VEC is a vector of I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 23 September 2005 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the length of the vectors. ! ! Input, integer A1(N), the vector to be copied. ! ! Output, integer A2(N), a copy of A1. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a1(n) integer a2(n) a2(1:n) = a1(1:n) return end subroutine i4vec_dec ( n, a ) !*****************************************************************************80 ! !! I4VEC_DEC decrements an I4VEC. ! ! Discussion: ! ! An I4VEC is a vector of I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of entries in the vector. ! ! Input/output, integer A(N), the vector to be decremented. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a(n) a(1:n) = a(1:n) - 1 return end subroutine i4vec_inc ( n, a ) !*****************************************************************************80 ! !! I4VEC_INC increments an I4VEC. ! ! Discussion: ! ! An I4VEC is a vector of I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of entries in the vector. ! ! Input/output, integer A(N), the vector to be incremented. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a(n) a(1:n) = a(1:n) + 1 return end function i4vec_max ( n, a ) !*****************************************************************************80 ! !! I4VEC_MAX computes the maximum element of an I4VEC. ! ! Discussion: ! ! An I4VEC is a vector of I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of entries in the array. ! ! Input, integer A(N), the array. ! ! Output, integer I4VEC_MAX, the value of the largest entry. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a(n) integer i4vec_max i4vec_max = maxval ( a(1:n) ) return end function i4vec_min ( n, a ) !*****************************************************************************80 ! !! I4VEC_MIN computes the minimum element of an I4VEC. ! ! Discussion: ! ! An I4VEC is a vector of I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of entries in the array. ! ! Input, integer A(N), the array. ! ! Output, integer I4VEC_MIN, the value of the smallest entry. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a(n) integer i4vec_min i4vec_min = minval ( a(1:n) ) return end subroutine i4vec_print ( n, a, title ) !*****************************************************************************80 ! !! I4VEC_PRINT prints an I4VEC. ! ! Discussion: ! ! An I4VEC is a vector of I4's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 May 2010 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of components of the vector. ! ! Input, integer A(N), the vector to be printed. ! ! Input, character ( len = * ) TITLE, a title. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a(n) integer i character ( len = * ) title write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) write ( *, '(a)' ) ' ' do i = 1, n write ( *, '(2x,i8,a,2x,i12)' ) i, ':', a(i) end do return end subroutine i4vec_write ( output_filename, n, x ) !*****************************************************************************80 ! !! I4VEC_WRITE writes an I4VEC file. ! ! Discussion: ! ! An I4VEC is a vector of I4 values. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) OUTPUT_FILENAME, the output file name. ! ! Input, integer N, the number of points. ! ! Input, integer X(N), the data. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer j character ( len = * ) output_filename integer output_status integer output_unit integer x(n) ! ! Open the file. ! call get_unit ( output_unit ) open ( unit = output_unit, file = output_filename, & status = 'replace', iostat = output_status ) if ( output_status /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'I4VEC_WRITE - Fatal error!' write ( *, '(a,i8)' ) ' Could not open the output file "' // & trim ( output_filename ) // '" on unit ', output_unit output_unit = -1 stop 1 end if ! ! Write the data. ! do j = 1, n write ( output_unit, '(i8)' ) x(j) end do ! ! Close the file. ! close ( unit = output_unit ) return end subroutine i4vec2_compare ( n, a1, a2, i, j, isgn ) !*****************************************************************************80 ! !! I4VEC2_COMPARE compares entries of an I4VEC2. ! ! Discussion: ! ! An I4VEC2 is a pair of I4VEC's. ! ! An I4VEC is a vector of I4's. ! ! Entry K of an I4VEC2 is the pair of values located ! at the K-th entries of the two I4VEC's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 October 1999 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of data items. ! ! Input, integer A1(N), A2(N), contain the two components ! of each item. ! ! Input, integer I, J, the items to be compared. ! ! Output, integer ISGN, the results of the comparison: ! -1, item I < item J, ! 0, item I = item J, ! +1, item J < item I. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a1(n) integer a2(n) integer i integer isgn integer j isgn = 0 if ( a1(i) < a1(j) ) then isgn = -1 else if ( a1(i) == a1(j) ) then if ( a2(i) < a2(j) ) then isgn = -1 else if ( a2(i) < a2(j) ) then isgn = 0 else if ( a2(j) < a2(i) ) then isgn = +1 end if else if ( a1(j) < a1(i) ) then isgn = +1 end if return end subroutine i4vec2_sort_a ( n, a1, a2 ) !*****************************************************************************80 ! !! I4VEC2_SORT_A ascending sorts a vector of pairs of integers. ! ! Discussion: ! ! An I4VEC2 is a pair of I4VEC's. ! ! An I4VEC is a vector of I4's. ! ! Entry K of an I4VEC2 is the pair of values located ! at the K-th entries of the two I4VEC's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 25 September 2001 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of items of data. ! ! Input/output, integer A1(N), A2(N), the data to be sorted. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a1(n) integer a2(n) integer i integer indx integer isgn integer j integer t if ( n <= 1 ) then return end if ! ! Initialize. ! i = 0 indx = 0 isgn = 0 j = 0 ! ! Call the external heap sorter. ! do call sort_heap_external ( n, indx, i, j, isgn ) ! ! Interchange the I and J objects. ! if ( 0 < indx ) then t = a1(i) a1(i) = a1(j) a1(j) = t t = a2(i) a2(i) = a2(j) a2(j) = t ! ! Compare the I and J objects. ! else if ( indx < 0 ) then call i4vec2_compare ( n, a1, a2, i, j, isgn ) else if ( indx == 0 ) then exit end if end do return end subroutine i4vec2_sorted_unique_count ( n, a1, a2, unique_num ) !*****************************************************************************80 ! !! I4VEC2_SORTED_UNIQUE_COUNT counts unique elements in a sorted I4VEC2. ! ! Discussion: ! ! An I4VEC2 is a pair of I4VEC's. ! ! An I4VEC is a vector of I4's. ! ! Entry K of an I4VEC2 is the pair of values located ! at the K-th entries of the two I4VEC's. ! ! Item I is stored as the pair A1(I), A2(I). ! ! The items must have been sorted, or at least it must be the ! case that equal items are stored in adjacent vector locations. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of items. ! ! Input, integer A1(N), A2(N), the items. ! ! Output, integer UNIQUE_NUM, the number of unique items. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer a1(n) integer a2(n) integer i integer iu integer unique_num if ( n <= 0 ) then unique_num = 0 return end if iu = 1 unique_num = 1 do i = 2, n if ( a1(i) /= a1(iu) .or. a2(i) /= a2(iu) ) then unique_num = unique_num + 1 iu = i end if end do return end subroutine i4vec2_sorted_uniquely ( n1, a1, b1, n2, a2, b2 ) !*****************************************************************************80 ! !! I4VEC2_SORTED_UNIQUELY copies unique elements from a sorted I4VEC2. ! ! Discussion: ! ! An I4VEC2 is a pair of I4VEC's. ! ! An I4VEC is a vector of I4's. ! ! Entry K of an I4VEC2 is the pair of values located ! at the K-th entries of the two I4VEC's. ! ! Item I is stored as the pair A1(I), A2(I). ! ! The items must have been sorted, or at least it must be the ! case that equal items are stored in adjacent vector locations. ! ! If the items were not sorted, then this routine will only ! replace a string of equal values by a single representative. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N1, the number of items. ! ! Input, integer A1(N1), B1(N1), the array of items. ! ! Input, integer N2, the number of unique items. ! ! Output, integer A2(N2), B2(N2), the array of unique items. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n1 integer n2 integer a1(n1) integer a2(n2) integer b1(n1) integer b2(n2) integer i1 integer i2 i1 = 1 i2 = 1 a2(i2) = a1(i1) b2(i2) = b1(i1) do i1 = 2, n1 if ( a1(i1) /= a2(i2) .or. b1(i1) /= b2(i2) ) then i2 = i2 + 1 a2(i2) = a1(i1) b2(i2) = b1(i1) end if end do return end function r8vec_diff_norm ( n, a, b ) !*****************************************************************************80 ! !! R8VEC_DIFF_NORM returns the L2 norm of the difference of R8VEC's. ! ! Discussion: ! ! An R8VEC is a vector of R8's. ! ! The vector L2 norm is defined as: ! ! R8VEC_NORM_L2 = sqrt ( sum ( 1 <= I <= N ) A(I)^2 ). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 April 2010 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of entries in A. ! ! Input, real ( kind = rk ) A(N), B(N), the vectors ! ! Output, real ( kind = rk ) R8VEC_DIFF_NORM, the L2 norm of A - B. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n real ( kind = rk ) a(n) real ( kind = rk ) b(n) real ( kind = rk ) r8vec_diff_norm r8vec_diff_norm = sqrt ( sum ( ( a(1:n) - b(1:n) )**2 ) ) return end subroutine r8vec_print ( n, a, title ) !*****************************************************************************80 ! !! R8VEC_PRINT prints an R8VEC. ! ! Discussion: ! ! An R8VEC is a vector of R8's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 22 August 2000 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer N, the number of components of the vector. ! ! Input, real ( kind = rk ) A(N), the vector to be printed. ! ! Input, character ( len = * ) TITLE, a title. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n real ( kind = rk ) a(n) integer i character ( len = * ) title write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) write ( *, '(a)' ) ' ' do i = 1, n write ( *, '(2x,i8,a,1x,g16.8)' ) i, ':', a(i) end do return end subroutine r8vec_uniform_01 ( n, seed, r ) !*****************************************************************************80 ! !! R8VEC_UNIFORM_01 returns a unit pseudorandom R8VEC. ! ! Discussion: ! ! An R8VEC is a vector of R8's. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 July 2006 ! ! Author: ! ! John Burkardt ! ! Reference: ! ! Paul Bratley, Bennett Fox, Linus Schrage, ! A Guide to Simulation, ! Springer Verlag, pages 201-202, 1983. ! ! Bennett Fox, ! Algorithm 647: ! Implementation and Relative Efficiency of Quasirandom ! Sequence Generators, ! ACM Transactions on Mathematical Software, ! Volume 12, Number 4, pages 362-376, 1986. ! ! Peter Lewis, Allen Goodman, James Miller ! A Pseudo-Random Number Generator for the System/360, ! IBM Systems Journal, ! Volume 8, pages 136-143, 1969. ! ! Parameters: ! ! Input, integer N, the number of entries in the vector. ! ! Input/output, integer SEED, the "seed" value, which ! should NOT be 0. On output, SEED has been updated. ! ! Output, real ( kind = rk ) R(N), the vector of pseudorandom values. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer i integer k integer seed real ( kind = rk ) r(n) if ( seed == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'R8VEC_UNIFORM_01 - Fatal error!' write ( *, '(a)' ) ' Input value of SEED = 0.' stop 1 end if do i = 1, n k = seed / 127773 seed = 16807 * ( seed - k * 127773 ) - k * 2836 if ( seed < 0 ) then seed = seed + 2147483647 end if r(i) = real ( seed, kind = rk ) * 4.656612875D-10 end do return end subroutine r8vec_write ( output_filename, n, x ) !*****************************************************************************80 ! !! R8VEC_WRITE writes an R8VEC file. ! ! Discussion: ! ! An R8VEC is a vector of R8 values. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 10 July 2011 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) OUTPUT_FILENAME, the output file name. ! ! Input, integer N, the number of points. ! ! Input, real ( kind = rk ) X(N), the data. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer j character ( len = * ) output_filename integer output_status integer output_unit real ( kind = rk ) x(n) ! ! Open the file. ! call get_unit ( output_unit ) open ( unit = output_unit, file = output_filename, & status = 'replace', iostat = output_status ) if ( output_status /= 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'R8VEC_WRITE - Fatal error!' write ( *, '(a,i8)' ) ' Could not open the output file "' // & trim ( output_filename ) // '" on unit ', output_unit output_unit = -1 stop 1 end if if ( 0 < n ) then ! ! Write the data. ! do j = 1, n write ( output_unit, '(2x,g24.16)' ) x(j) end do end if ! ! Close the file. ! close ( unit = output_unit ) return end subroutine sort_heap_external ( n, indx, i, j, isgn ) !*****************************************************************************80 ! !! SORT_HEAP_EXTERNAL externally sorts a list of items into ascending order. ! ! Discussion: ! ! The actual list of data is not passed to the routine. Hence this ! routine may be used to sort integers, reals, numbers, names, ! dates, shoe sizes, and so on. After each call, the routine asks ! the user to compare or interchange two items, until a special ! return value signals that the sorting is completed. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 05 February 2004 ! ! Author: ! ! Original FORTRAN77 version by Albert Nijenhuis, Herbert Wilf. ! FORTRAN90 version by John Burkardt. ! ! Reference: ! ! Albert Nijenhuis, Herbert Wilf, ! Combinatorial Algorithms for Computers and Calculators, ! Academic Press, 1978, ! ISBN: 0-12-519260-6, ! LC: QA164.N54. ! ! Parameters: ! ! Input, integer N, the number of items to be sorted. ! ! Input/output, integer INDX, the main communication signal. ! The user must set INDX to 0 before the first call. ! Thereafter, the user should not change the value of INDX until ! the sorting is done. ! On return, if INDX is ! *greater than 0, ! ...interchange items I and J; ! ...call again. ! *less than 0, ! ...compare items I and J; ! ...set ISGN = -1 if I < J, ISGN = +1 if J < I; ! ...call again. ! * equal to 0, ! ...the sorting is done. ! ! Output, integer I, J, the indices of two items. ! On return with INDX positive, elements I and J should be interchanged. ! On return with INDX negative, elements I and J should be compared, and ! the result reported in ISGN on the next call. ! ! Input, integer ISGN, results of comparison of elements ! I and J. (Used only when the previous call returned INDX less than 0). ! ISGN <= 0 means I is less than or equal to J; ! 0 <= ISGN means I is greater than or equal to J. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer i integer, save :: i_save = 0 integer indx integer isgn integer j integer, save :: j_save = 0 integer, save :: k = 0 integer, save :: k1 = 0 integer n integer, save :: n1 = 0 ! ! INDX = 0: This is the first call. ! if ( indx == 0 ) then i_save = 0 j_save = 0 k = n / 2 k1 = k n1 = n ! ! INDX < 0: The user is returning the results of a comparison. ! else if ( indx < 0 ) then if ( indx == -2 ) then if ( isgn < 0 ) then i_save = i_save + 1 end if j_save = k1 k1 = i_save indx = -1 i = i_save j = j_save return end if if ( 0 < isgn ) then indx = 2 i = i_save j = j_save return end if if ( k <= 1 ) then if ( n1 == 1 ) then i_save = 0 j_save = 0 indx = 0 else i_save = n1 n1 = n1 - 1 j_save = 1 indx = 1 end if i = i_save j = j_save return end if k = k - 1 k1 = k ! ! 0 < INDX, the user was asked to make an interchange. ! else if ( indx == 1 ) then k1 = k end if do i_save = 2 * k1 if ( i_save == n1 ) then j_save = k1 k1 = i_save indx = -1 i = i_save j = j_save return else if ( i_save <= n1 ) then j_save = i_save + 1 indx = -2 i = i_save j = j_save return end if if ( k <= 1 ) then exit end if k = k - 1 k1 = k end do if ( n1 == 1 ) then i_save = 0 j_save = 0 indx = 0 i = i_save j = j_save else i_save = n1 n1 = n1 - 1 j_save = 1 indx = 1 i = i_save j = j_save end if return end subroutine st_data_read ( input_filename, m, n, nst, ist, jst, ast ) !*****************************************************************************80 ! !! ST_DATA_READ reads the data of an ST file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) INPUT_FILENAME, the name of the ST file. ! ! Input, integer M, the number of rows. ! ! Input, integer N, the number of columns. ! ! Input, integer NST, the number of ST elements. ! ! Output, integer IST(NST), JST(NST), the ST rows and columns. ! ! Output, real ( kind = rk ) AST(NST), the ST values. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer nst real ( kind = rk ) aij real ( kind = rk ) ast(nst) integer i character ( len = * ) input_filename integer input_unit integer ios integer ist(nst) integer jst(nst) integer j integer k integer m integer n call i4_fake_use ( m ) call i4_fake_use ( n ) call get_unit ( input_unit ) open ( file = input_filename, unit = input_unit, status = 'old', & iostat = ios ) do k = 1, nst read ( input_unit, *, iostat = ios ) i, j, aij if ( ios /= 0 ) then exit end if ist(k) = i jst(k) = j ast(k) = aij end do close ( unit = input_unit ) return end subroutine st_header_print ( i_min, i_max, j_min, j_max, m, n, nst ) !*****************************************************************************80 ! !! ST_HEADER_PRINT prints the header of an ST file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer I_MIN, I_MAX, the minimum and maximum rows. ! ! Input, integer J_MIN, J_MAX, the minimum and maximum columns. ! ! Input, integer M, N, the number of rows and columns. ! ! Input, integer NST, the number of nonzeros. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer i_max integer i_min integer j_max integer j_min integer m integer n integer nst write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Sparse Triplet (ST) header information:' write ( *, '(a)' ) ' ' write ( *, '(a,i8)' ) ' Minimum row index I_MIN = ', i_min write ( *, '(a,i8)' ) ' Maximum row index I_MAX = ', i_max write ( *, '(a,i8)' ) ' Minimum col index J_MIN = ', j_min write ( *, '(a,i8)' ) ' Maximum col index J_MAX = ', j_max write ( *, '(a,i8)' ) ' Number of rows M = ', m write ( *, '(a,i8)' ) ' Number of columns N = ', n write ( *, '(a,i8)' ) ' Number of nonzeros NST = ', nst return end subroutine st_header_read ( input_filename, i_min, i_max, j_min, j_max, & m, n, nst ) !*****************************************************************************80 ! !! ST_HEADER_READ reads the header of an ST file. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 21 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, character ( len = * ) INPUT_FILENAME, the name of the ST file. ! ! Output, integer I_MIN, I_MAX, the minimum and maximum rows. ! ! Output, integer J_MIN, J_MAX, the minimum and maximum columns. ! ! Output, integer M, N, the number of rows and columns. ! ! Output, integer NST, the number of nonzeros. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) real ( kind = rk ) aij integer i integer i_max integer i_min integer, parameter :: i4_huge = 2147483647 character ( len = * ) input_filename integer input_unit integer ios integer j integer j_max integer j_min integer m integer n integer nst call get_unit ( input_unit ) open ( file = input_filename, unit = input_unit, status = 'old', & iostat = ios ) nst = 0 i_min = + i4_huge i_max = - i4_huge j_min = + i4_huge j_max = - i4_huge do read ( input_unit, *, iostat = ios ) i, j, aij if ( ios /= 0 ) then exit end if nst = nst + 1 i_min = min ( i_min, i ) i_max = max ( i_max, i ) j_min = min ( j_min, j ) j_max = max ( j_max, j ) end do close ( unit = input_unit ) m = i_max - i_min + 1 n = j_max - j_min + 1 return end subroutine st_mv ( m, n, nst, ist, jst, ast, x, b ) !*****************************************************************************80 ! !! ST_MV multiplies an R8SP matrix by an R8VEC. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 13 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer M, N, the number of rows and columns of ! the matrix. ! ! Input, integer NST, the number of nonzero elements in ! the matrix. ! ! Input, integer IST(NST), JST(NST), the row and ! column indices of the nonzero elements. ! ! Input, real ( kind = rk ) AST(NST), the nonzero elements of the matrix. ! ! Input, real ( kind = rk ) X(N), the vector to be multiplied by A. ! ! Output, real ( kind = rk ) B(M), the product vector A*X. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer m integer n integer nst real ( kind = rk ) ast(nst) real ( kind = rk ) b(m) integer i integer ist(nst) integer j integer jst(nst) integer k real ( kind = rk ) x(n) b(1:m) = 0.0D+00 do k = 1, nst i = ist(k) j = jst(k) b(i) = b(i) + ast(k) * x(j) end do return end subroutine st_print ( m, n, nst, ist, jst, ast, title ) !*****************************************************************************80 ! !! ST_PRINT prints a sparse matrix in ST format. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer M, the number of rows. ! ! Input, integer N, the number of columns. ! ! Input, integer NST, the number of ST elements. ! ! Input, integer IST(NST), JST(NST), the ST rows and columns. ! ! Input, real ( kind = rk ) AST(NST), the ST values. ! ! Input, character ( len = * ) TITLE, a title. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer nst real ( kind = rk ) ast(nst) integer ist(nst) integer jst(nst) integer k integer m integer n character ( len = * ) title call i4_fake_use ( m ) call i4_fake_use ( n ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) trim ( title ) write ( *, '(a)' ) ' # I J A' write ( *, '(a)' ) ' ---- ---- ---- --------------' write ( *, '(a)' ) ' ' do k = 1, nst write ( *, '(2x,i4,2x,i4,2x,i4,2x,g16.8)' ) k, ist(k), jst(k), ast(k) end do return end subroutine st_to_ccs_index ( nst, ist, jst, ncc, n, icc, ccc ) !*****************************************************************************80 ! !! ST_TO_ccs_INDEX creates CCS indices from ST data. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer NST, the number of ST elements. ! ! Input, integer IST(NST), JST(NST), the ST rows and columns. ! ! Input, integer NCC, the number of CCS elements. ! ! Input, integer N, the number of columns in the matrix. ! ! Output, integer ICC(NCC), the CCS rows. ! ! Output, integer CCC(N+1), the compressed CCS columns. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer ncc integer nst integer ccc(n+1) integer i integer icc(ncc) integer ist(nst) integer ist2(nst) integer jhi integer jlo integer jcc(ncc) integer jst(nst) integer jst2(nst) ! ! Make copies so the sorting doesn't confuse the user. ! call i4vec_copy ( nst, ist, ist2 ) call i4vec_copy ( nst, jst, jst2 ) ! ! Sort the elements. ! call i4vec2_sort_a ( nst, jst2, ist2 ) ! ! Get the unique elements. ! call i4vec2_sorted_uniquely ( nst, jst2, ist2, ncc, jcc, icc ) ! ! Compress the column index. ! ccc(1) = 1 jlo = 1 do i = 1, ncc jhi = jcc(i) if ( jhi /= jlo ) then ccc(jlo+1:jhi) = i jlo = jhi end if end do jhi = n + 1 ccc(jlo+1:jhi) = ncc + 1 return end subroutine st_to_ccs_size ( nst, ist, jst, ncc ) !*****************************************************************************80 ! !! ST_TO_ccs_SIZE sizes CCS indexes based on ST data. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer NST, the number of ST elements. ! ! Input, integer IST(NST), JST(NST), the ST rows and columns. ! ! Output, integer NCC, the number of CCS elements. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer nst integer ist(nst) integer ist2(nst) integer jst2(nst) integer jst(nst) integer ncc ! ! Make copies so the sorting doesn't confuse the user. ! call i4vec_copy ( nst, ist, ist2 ) call i4vec_copy ( nst, jst, jst2 ) ! ! Sort by column first, then row. ! call i4vec2_sort_a ( nst, jst2, ist2 ) ! ! Count the unique pairs. ! call i4vec2_sorted_unique_count ( nst, jst2, ist2, ncc ) return end subroutine st_to_ccs_values ( nst, ist, jst, ast, ncc, n, icc, ccc, acc ) !*****************************************************************************80 ! !! ST_TO_ccs_VALUES creates CCS values from ST data. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 12 July 2014 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! Input, integer NST, the number of ST elements. ! ! Input, integer IST(NST), JST(NST), the ST rows and columns. ! ! Input, real ( kind = rk ) AST(NST), the ST values. ! ! Input, integer NCC, the number of CCS elements. ! ! Input, integer N, the number of columns. ! ! Input, integer ICC(NCC), the CCS rows. ! ! Input, integer CCC(N+1), the CCS compressed columns. ! ! Output, real ( kind = rk ) ACC(NCC), the CCS values. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer n integer ncc integer nst real ( kind = rk ) ast(nst) real ( kind = rk ) acc(ncc) integer ccc(n+1) integer chi integer clo logical fail integer i integer icc(ncc) integer ist(nst) integer j integer jst(nst) integer kcc integer kst acc(1:ncc) = 0.0D+00 do kst = 1, nst i = ist(kst) j = jst(kst) clo = ccc(j) chi = ccc(j+1) fail = .true. do kcc = clo, chi - 1 if ( icc(kcc) == i ) then acc(kcc) = acc(kcc) + ast(kst) fail = .false. exit end if end do if ( fail ) then write ( *, '(a)' ) '' write ( *, '(a)' ) 'ST_TO_ccs_VALUES - Fatal error!' write ( *, '(a)' ) ' ST entry cannot be located in CCS array.' write ( *, '(a,i4)' ) ' ST index KST = ', kst write ( *, '(a,i4)' ) ' ST row IST(KST) = ', ist(kst) write ( *, '(a,i4)' ) ' ST col JST(KST) = ', jst(kst) write ( *, '(a,g14.6)' ) ' ST val AST(KST) = ', ast(kst) stop 1 end if end do return end subroutine timestamp ( ) !*****************************************************************************80 ! !! TIMESTAMP prints the current YMDHMS date as a time stamp. ! ! Example: ! ! 31 May 2001 9:45:54.872 AM ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 18 May 2013 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! None ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) character ( len = 8 ) ampm integer d integer h integer m integer mm character ( len = 9 ), parameter, dimension(12) :: month = (/ & 'January ', 'February ', 'March ', 'April ', & 'May ', 'June ', 'July ', 'August ', & 'September', 'October ', 'November ', 'December ' /) integer n integer s integer values(8) integer y call date_and_time ( values = values ) y = values(1) m = values(2) d = values(3) h = values(5) n = values(6) s = values(7) mm = values(8) if ( h < 12 ) then ampm = 'AM' else if ( h == 12 ) then if ( n == 0 .and. s == 0 ) then ampm = 'Noon' else ampm = 'PM' end if else h = h - 12 if ( h < 12 ) then ampm = 'PM' else if ( h == 12 ) then if ( n == 0 .and. s == 0 ) then ampm = 'Midnight' else ampm = 'AM' end if end if end if write ( *, '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' ) & d, trim ( month(m) ), y, h, ':', n, ':', s, '.', mm, trim ( ampm ) return end subroutine wathen_st ( nx, ny, nz_num, row, col, a ) !*****************************************************************************80 ! !! WATHEN_ST: Wathen matrix stored in sparse triplet (ST) format. ! ! Discussion: ! ! When dealing with sparse matrices in MATLAB, it can be much more efficient ! to work first with a triple of I, J, and X vectors, and only once ! they are complete, convert to MATLAB's sparse format. ! ! The Wathen matrix is a finite element matrix which is sparse. ! ! The entries of the matrix depend in part on a physical quantity ! related to density. That density is here assigned random values between ! 0 and 100. ! ! The matrix order N is determined by the input quantities NX and NY, ! which would usually be the number of elements in the X and Y directions. ! ! The value of N is ! ! N = 3*NX*NY + 2*NX + 2*NY + 1, ! ! The matrix is the consistent mass matrix for a regular NX by NY grid ! of 8 node serendipity elements. ! ! The local element numbering is ! ! 3--2--1 ! | | ! 4 8 ! | | ! 5--6--7 ! ! Here is an illustration for NX = 3, NY = 2: ! ! 23-24-25-26-27-28-29 ! | | | | ! 19 20 21 22 ! | | | | ! 12-13-14-15-16-17-18 ! | | | | ! 8 9 10 11 ! | | | | ! 1--2--3--4--5--6--7 ! ! For this example, the total number of nodes is, as expected, ! ! N = 3 * 3 * 2 + 2 * 2 + 2 * 3 + 1 = 29 ! ! The matrix is symmetric positive definite for any positive values of the ! density RHO(X,Y). ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 02 July 2014 ! ! Author: ! ! John Burkardt. ! ! Reference: ! ! Nicholas Higham, ! Algorithm 694: A Collection of Test Matrices in MATLAB, ! ACM Transactions on Mathematical Software, ! Volume 17, Number 3, September 1991, pages 289-305. ! ! Andrew Wathen, ! Realistic eigenvalue bounds for the Galerkin mass matrix, ! IMA Journal of Numerical Analysis, ! Volume 7, Number 4, October 1987, pages 449-457. ! ! Parameters: ! ! Input, integer NX, NY, values which determine the size of ! the matrix. ! ! Input, integer NZ_NUM, the number of values used to ! describe the matrix. ! ! Output, integer ROW(NZ_NUM), COL(NZ_NUM), the row and ! column indices of the nonzero entries. ! ! Output, real ( kind = rk ) A(NZ_NUM), the nonzero entries of the matrix. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer nx integer ny integer nz_num real ( kind = rk ) a(nz_num) integer col(nz_num) real ( kind = rk ), dimension ( 8, 8 ), save :: em = reshape ( (/ & 6.0, -6.0, 2.0, -8.0, 3.0, -8.0, 2.0, -6.0, & -6.0, 32.0, -6.0, 20.0, -8.0, 16.0, -8.0, 20.0, & 2.0, -6.0, 6.0, -6.0, 2.0, -8.0, 3.0, -8.0, & -8.0, 20.0, -6.0, 32.0, -6.0, 20.0, -8.0, 16.0, & 3.0, -8.0, 2.0, -6.0, 6.0, -6.0, 2.0, -8.0, & -8.0, 16.0, -8.0, 20.0, -6.0, 32.0, -6.0, 20.0, & 2.0, -8.0, 3.0, -8.0, 2.0, -6.0, 6.0, -6.0, & -6.0, 20.0, -8.0, 16.0, -8.0, 20.0, -6.0, 32.0 /), & (/ 8, 8 /) ) integer i integer j integer k integer kcol integer krow integer node(8) real ( kind = rk ) rho integer row(nz_num) row(1:nz_num) = 0 col(1:nz_num) = 0 a(1:nz_num) = 0.0D+00 k = 0 do j = 1, ny do i = 1, nx node(1) = 3 * j * nx + 2 * j + 2 * i + 1 node(2) = node(1) - 1 node(3) = node(1) - 2 node(4) = ( 3 * j - 1 ) * nx + 2 * j + i - 1 node(5) = ( 3 * j - 3 ) * nx + 2 * j + 2 * i - 3 node(6) = node(5) + 1 node(7) = node(5) + 2 node(8) = node(4) + 1 call random_number ( harvest = rho ) rho = 100.0D+00 * rho do krow = 1, 8 do kcol = 1, 8 k = k + 1 row(k) = node(krow) col(k) = node(kcol) a(k) = rho * em(krow,kcol) end do end do end do end do return end subroutine wathen_st_size ( nx, ny, nz_num ) !*****************************************************************************80 ! !! WATHEN_ST_SIZE: Size of Wathen matrix stored in sparse triplet format. ! ! Licensing: ! ! This code is distributed under the MIT license. ! ! Modified: ! ! 04 June 2014 ! ! Author: ! ! John Burkardt. ! ! Reference: ! ! Nicholas Higham, ! Algorithm 694: A Collection of Test Matrices in MATLAB, ! ACM Transactions on Mathematical Software, ! Volume 17, Number 3, September 1991, pages 289-305. ! ! Andrew Wathen, ! Realistic eigenvalue bounds for the Galerkin mass matrix, ! IMA Journal of Numerical Analysis, ! Volume 7, Number 4, October 1987, pages 449-457. ! ! Parameters: ! ! Input, integer NX, NY, values which determine the size of the matrix. ! ! Output, integer NZ_NUM, the number of items of data used to describe ! the matrix. ! implicit none integer, parameter :: rk = kind ( 1.0D+00 ) integer nx integer ny integer nz_num nz_num = nx * ny * 64 return end