You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

matriz.sh 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. #!/bin/bash
  2. # author: liam beckman
  3. # created: 2018-04-03
  4. # updated: 2018-04-23
  5. # sources:
  6. # https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
  7. # p1gradingscript, Written by Ryan Gambord (gambordr@oregonstate.edu)
  8. # https://stackoverflow.com/questions/8550385/how-to-read-1-line-from-2-files-sequentially
  9. # https://www.poetryfoundation.org/poems/142199/lines-of-force
  10. # control-c will terminate script execution and remove temporary files
  11. trap "echo; echo 'SIGINT received: Deleting temp files then exiting!'; clean; exit 1" INT
  12. # Parse any args
  13. fancy=0
  14. POSITIONAL=()
  15. while [ $# -gt 0 ]
  16. do
  17. if [[ $1 == "--fancy" ]] || [[ $1 == "-f" ]]
  18. then
  19. # output fancy message
  20. fancy=1
  21. shift
  22. fi
  23. # save it in an array for later
  24. POSITIONAL+=("$1")
  25. # shift past argument
  26. shift
  27. done
  28. # restore positional parameters
  29. set -- "${POSITIONAL[@]}"
  30. # valiadate user's matrices
  31. validate()
  32. {
  33. # clear temporary validate file
  34. > validate$$.temp
  35. if [ ! -f $1 ] || [ ! -r $1 ]
  36. then
  37. echo "$1 is an unreadable file" >&2
  38. exit 1
  39. fi
  40. read entireline < $1
  41. x1=0
  42. for i in $entireline
  43. do
  44. x1=$((x1 + 1))
  45. done
  46. # An empty matrix.
  47. if [ ! -s $1 ]
  48. then
  49. echo "empty matrix error" >&2
  50. exit 1
  51. fi
  52. # A matrix where the final entry on a row is followed by a tab character.
  53. tail -n 1 $1 >> validate$$.temp
  54. # trailing tabs error
  55. trailingTab=0
  56. trailingTab=$(grep -c $'\t'$ validate$$.temp)
  57. #trailingTabOrSpace=$(grep -c '[[:blank:]]$' validate$$.temp)
  58. if [ $trailingTab -gt 0 ]
  59. then
  60. echo "trailing tabs error at last row in $1" >&2
  61. exit 1
  62. fi
  63. y=1
  64. while read line
  65. do
  66. # A matrix with empty lines.
  67. if [ -z "$line" ]
  68. then
  69. echo "empty line error at row $y in $1" >&2
  70. exit 1
  71. fi
  72. x=0
  73. for element in $line
  74. do
  75. # A matrix with any element that is not an integer.
  76. if [ $element -eq $element ] 2>/dev/null
  77. then
  78. ((x++))
  79. else
  80. echo "non-numeric element error in $1: $element" >&2
  81. exit 1
  82. fi
  83. done
  84. # A matrix with any element that is blank.
  85. if [ $x -lt $x1 ]
  86. then
  87. echo "blank element at column $x, row $y in $1" >&2
  88. exit 1
  89. fi
  90. ((y++))
  91. done < $1
  92. #rm -f validate$$.temp
  93. }
  94. dims()
  95. {
  96. # clear temporary dims file
  97. > dims$$.temp
  98. rows=0
  99. cols=0
  100. # read in columns
  101. read entireline < $1
  102. for i in $entireline
  103. do
  104. cols=$((cols + 1))
  105. done
  106. # read in rows
  107. rows=$(wc -l < $1)
  108. echo -n $rows
  109. echo -n " "
  110. echo -n $cols
  111. echo
  112. echo $cols >> dims$$.temp
  113. echo $rows >> dims$$.temp
  114. }
  115. transpose()
  116. {
  117. # clear temporary transpose file
  118. > transpose$$.temp
  119. # if there is a file being read in...
  120. if [ $1 ]
  121. then dims $1 &> /dev/null
  122. # otherwise we're reading from stdin
  123. else
  124. dims stdinLeft$$.temp &> /dev/null
  125. fi
  126. x1="$(head -n 1 dims$$.temp)"
  127. # convert columns to rows
  128. for i in $(seq 1 $x1)
  129. do
  130. cut -f$i $1 | paste -s >> transpose$$.temp
  131. done
  132. # output transpose matrix to stdin
  133. cat transpose$$.temp
  134. }
  135. mean()
  136. {
  137. # clear temporary dims file
  138. > mean$$.temp
  139. dims $1 &> /dev/null
  140. x1="$(head -n 1 dims$$.temp)"
  141. # prime the transpose$$.temp file
  142. transpose $1 &> /dev/null
  143. # the x-coordinate of the current column of the ouput. Used for outputting newlines.
  144. endOfLine=0
  145. while read line
  146. do
  147. sum=0
  148. count=0
  149. average=0
  150. # for all elements in the matrix
  151. for element in $line
  152. do
  153. # add element to the total sum
  154. sum=$((sum + element))
  155. ((count++))
  156. done
  157. average=$(((sum + (count/2)*( (sum>0)*2-1 )) / count))
  158. # increment the x-coordinate of the mean row
  159. ((endOfLine++))
  160. # if we have not reached the end of the row...
  161. if [ $endOfLine -lt $x1 ]
  162. then
  163. # just print the mean and a tab
  164. printf "%s\t" "$average"
  165. else
  166. # otherwise print the mean
  167. printf "%s" "$average"
  168. fi
  169. done < transpose$$.temp
  170. echo
  171. }
  172. add()
  173. {
  174. # clear temporary add files
  175. > addLeft$$.temp
  176. > addRight$$.temp
  177. dims $1 &> /dev/null
  178. x1="$(head -n 1 dims$$.temp)"
  179. y1="$(tail -n 1 dims$$.temp)"
  180. dims $2 &> /dev/null
  181. x2="$(head -n 1 dims$$.temp)"
  182. y2="$(tail -n 1 dims$$.temp)"
  183. if [ $x1 -ne $x2 ] || [ $y1 -ne $y2 ]
  184. then
  185. echo -e "\e[1;31mERROR\e[0m: matrix dimensions do not match" >&2 # Print error message if at top
  186. echo -e "matrix one: \e[1;31m$y1 x $x1\e[0m" >&2
  187. echo -e "matrix two: \e[1;31m$y2 x $x2\e[0m" >&2
  188. exit 1
  189. fi
  190. # convert first matrix into a "X by 1" matrix in temp file
  191. # this will make it easier to draw elements from
  192. cat $1 | tr '\t' '\n' >> addLeft$$.temp
  193. # convert second matrix into a "X by 1" matrix in temp file
  194. # this will make it easier to draw elements from
  195. cat $2 | tr '\t' '\n' >> addRight$$.temp
  196. # the given column number of the sum matrix. Used for outputting newlines.
  197. endOfLine=0
  198. # read in both matrices and add elements
  199. while read left && read right <&3
  200. do
  201. # calculate sum
  202. sum=$((left + right))
  203. # increment the x-coordinate of the sum matrix
  204. ((endOfLine++))
  205. # if we have not reached the end of the row...
  206. if [ $endOfLine -lt $x1 ]
  207. then
  208. # just print the mean and a tab
  209. printf "%s\t" $sum
  210. else
  211. # otherwise print the mean
  212. printf "%s" $sum
  213. echo
  214. # reset column position of product matrix
  215. endOfLine=0
  216. fi
  217. done < addLeft$$.temp 3< addRight$$.temp
  218. }
  219. multiply()
  220. {
  221. # clear temporary multiply files
  222. > multiplyLeft$$.temp
  223. > multiplyRight$$.temp
  224. # transpose second matrix to make it easier to read in elements
  225. transpose $2 &> /dev/null
  226. # get first matrix's dimensions
  227. dims $1 &> /dev/null
  228. x1="$(head -n 1 dims$$.temp)"
  229. y1="$(tail -n 1 dims$$.temp)"
  230. # get second matrix's dimensions
  231. dims $2 &> /dev/null
  232. x2="$(head -n 1 dims$$.temp)"
  233. y2="$(tail -n 1 dims$$.temp)"
  234. # error message for misproportioned matrices
  235. if [ $x1 -ne $y2 ]
  236. then
  237. echo -e "\e[1;31mERROR\e[0m: matrix dimensions do not match" >&2
  238. echo -e "matrix one: $y1 x \e[1;31m$x1\e[0m" >&2
  239. echo -e "matrix two: \e[1;31m$y2\e[0m x $x2" >&2
  240. exit 1
  241. fi
  242. # add first matrix into array
  243. arr2=0
  244. while read line
  245. do
  246. for element in $line
  247. do
  248. arr2+=($element)
  249. done
  250. done < $1
  251. # add second matrix into array
  252. arr3=0
  253. while read line
  254. do
  255. for element in $line
  256. do
  257. #echo "element: $element"
  258. arr3+=($element)
  259. #echo arr2
  260. done
  261. done < $2
  262. # the number of processed rows in the first matrix
  263. rowTotal=0
  264. # the x-coordinate of the current column of the first matrix. Used for outputting newlines.
  265. endOfLine=0
  266. while read line
  267. do
  268. # the column that is currently being processed
  269. columnIndex=0
  270. while [ $columnIndex -lt $x2 ]
  271. do
  272. # the number of processed columns in the second matrix
  273. columnTotal=0
  274. # the row that is currently being processed
  275. rowIndex=0
  276. # sum of multiplications between elements.
  277. sum=0
  278. while [ $columnTotal -lt $x1 ]
  279. do
  280. # left element in multiplication
  281. left=${arr2[$x1 * $rowTotal + $rowIndex + 1 ]}
  282. # right element in multiplication
  283. right=${arr3[$x2 * $columnTotal + $columnIndex + 1]}
  284. #add to sum the product of the left and right elements
  285. sum=$((sum + left * right))
  286. #increment the total number of columns that have been processed
  287. ((columnTotal++))
  288. #increment the row index of the first matrix
  289. ((rowIndex++))
  290. done
  291. #increment the column index of the second matrix
  292. ((columnIndex++))
  293. # increment the x-coordinate of the product matrix
  294. ((endOfLine++))
  295. # if we have not reached the end of the row...
  296. if [ $endOfLine -lt $x2 ]
  297. then
  298. # just print the sum and a tab
  299. printf "%s\t" $sum
  300. else
  301. # otherwise print the sum
  302. printf "%s" $sum
  303. # enter new row in product matrix
  304. echo
  305. # reset column position of product matrix
  306. endOfLine=0
  307. fi
  308. done
  309. #increment the total number of rows that have been processed
  310. ((rowTotal++))
  311. done < $1
  312. runtime=$((end-start))
  313. echo $runtime > timeMultiply.temp
  314. }
  315. clean()
  316. {
  317. # remove temporary files
  318. rm -f addLeft$$.temp
  319. rm -f addRight$$.temp
  320. rm -f dims*.temp
  321. rm -f mean$$.temp
  322. rm -f multiplyLeft*.temp
  323. rm -f multiplyRight*.temp
  324. rm -f stdinLeft$$.temp
  325. rm -f stdinRight$$.temp
  326. rm -f transpose*.temp
  327. rm -f validate*.temp
  328. }
  329. fancyGoodbye()
  330. {
  331. echo
  332. echo "  Don't worry, __
  333. \"Bee\" happy! // \\
  334. \\\_/ //
  335. ''-.._.-''-.._.. -(||)(')
  336. '''"
  337. }
  338. main()
  339. {
  340. # inavlid number of operations provided
  341. [ $# -gt 4 ] && echo "too many arguments specified" >&2 && exit 1
  342. # validate input
  343. if [ $# -eq 2 ]
  344. then
  345. validate $2
  346. elif [ $# -eq 3 ]
  347. then
  348. validate $2
  349. validate $3
  350. fi
  351. # functions that accept input from stdin
  352. if [ $1 = "dims" ] || [ $1 = "transpose" ] || [ $1 = "mean" ]
  353. then
  354. # read from standard input
  355. if [ $# -eq 1 ]
  356. then
  357. cat > stdinLeft$$.temp
  358. cat > stdinRight$$.temp
  359. # validate input
  360. if [ -s stdinLeft$$.temp ]
  361. then
  362. validate stdinLeft$$.temp
  363. fi
  364. if [ -s stdinRight$$.temp ]
  365. then
  366. validate stdinRight$$.temp
  367. fi
  368. fi
  369. else
  370. # inavlid number of operations provided
  371. [ $# -lt 2 ] && echo "too few arguments specified" >&2 && exit 1
  372. fi
  373. case $1 in
  374. # call dims function
  375. dims)
  376. if [ $2 ];
  377. then
  378. dims $2
  379. else
  380. dims stdinLeft$$.temp
  381. fi
  382. ;;
  383. # call transpose function
  384. transpose)
  385. if [ $2 ];
  386. then
  387. transpose $2
  388. else
  389. transpose stdinLeft$$.temp
  390. fi
  391. ;;
  392. # call mean function
  393. mean)
  394. if [ $2 ];
  395. then
  396. mean $2
  397. else
  398. mean stdinLeft$$.temp
  399. fi
  400. ;;
  401. # call add function
  402. add)
  403. add $2 $3
  404. ;;
  405. # call multiply function
  406. multiply)
  407. multiply $2 $3
  408. ;;
  409. # invalid operation provided
  410. *)
  411. echo "unknown operation provided" >&2
  412. ;;
  413. esac
  414. # call fancy goodbye function
  415. if [ $fancy -eq 1 ]
  416. then
  417. fancyGoodbye
  418. fi
  419. # call clean function and remove temporary files
  420. clean
  421. }
  422. # call main function with all arguments
  423. main $@
  424. # ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~
  425. # P O E T R Y of the M O N T H
  426. # ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~
  427. #
  428. # Lines of Force
  429. # By Thomas Centolella
  430. #
  431. # ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~
  432. #
  433. # The pleasure of walking a long time on the mountain
  434. # without seeing a human being, much less speaking to one.
  435. #
  436. # And the pleasure of speaking when one is suddenly there.
  437. # The upgrade from wary to tolerant to convivial,
  438. # so unlike two brisk bodies on a busy street
  439. # for whom a sudden magnetic attraction
  440. # is a mistake, awkwardness, something to be sorry for.
  441. #
  442. # But to loiter, however briefly, in a clearing
  443. # where two paths intersect in the matrix of chance.
  444. # To stop here speaking the few words that come to mind.
  445. # A greeting. Some earnest talk of weather.
  446. # A little history of the day.
  447. #
  448. # To stand there then and say nothing.
  449. # To slowly look around past each other.
  450. # Notice the green tang pines exude in the heat
  451. # and the denser sweat of human effort.
  452. #
  453. # To have nothing left to say
  454. # but not wanting just yet to move on.
  455. # The tension between you, a gossamer thread.
  456. # It trembles in the breeze, holding
  457. # the thin light it transmits.
  458. #
  459. # To be held in that
  460. # line of force, however briefly,
  461. # as if it were all that mattered.
  462. #
  463. # And then to move on.
  464. # With equal energy, with equal pleasure.
  465. #
  466. # ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~