Trace dependents & precedents of a program in an imperative language
The analysis you want is called reaching definitions in the compiler community.

For your case you would put a "fake" definition of each variable you are interested in at the beginning of the program (representing definitions that are entering your script from outside) and then determine whether that definition reaches any of the uses.  If no fake definition reaches any use then the variable is defined inside the script, otherwise its value may be coming in from outside. The interesting cases involve conditionals and loops (some variables may be defined on one side of a conditional and not the other.)

I can highly recommend the following text books if you want to learn more:


Aho, Alfred V.; Sethi, Ravi;  Ullman, Jeffrey D.: Compilers: Principles, Techniques, and Tools, 1986.
Cooper, Keith D.; Torczon, Linda: Engineering a Compiler, 2005.


Reaching definitions analyzes scalars (so you would analyze each a[i,j] independently, as you did in your example.)

You could try to analyze entire arrays simultaneously, but this is a research topic (because parts of the array can be defined and other parts not).  The classic papers on trying to analyze entire arrays are 


Zhiyuan Li: Array privatization for parallel execution of loops. Int'l Conf on Supercomputing, 1992.
Dror E. Maydan, Saman P. Amarasinghe, and Monica S. Lam: Array data-ﬂow analysis and its use in array privatization. Symp Principles of Programming Languages, (POPL-20):2-15, 1993.
Peng Tu and David Padua. Automatic array privatization. Int'l Workshop
on Languages and Compilers for Parallel Computing, (LCPC-6):500–521, 1993.