Introduction to Problem Solving

Steps in Programming

      A Very Simplified Picture

 

     Problem Definition & Analysis

     High Level Strategy for a solution

     Arriving at an algorithm

     Verification and analysis of the algorithm

     Encoding the algorithm as a program

       (in a programming language)

     Testing the program

 

      Each step iterative and the whole process also iterative

Problem Definition & Analysis

      Understanding the problem is half the solution

      A precise solution requires a precise definition

      This step leads to clear definition of the problem

      The definition states WHAT the problem to be solved

      rather than HOW the problem to be solved

      Analysis done to get a complete and consistent specification

      Specification precisely and unambiguously states

   Constraints on the inputs

   Desired Properties of the outputs

High Level Strategy

      This is a crucial and most difficult step

      Most creative part of the whole process

      No standard recipe for arriving at a strategy

      There do exist many standard techniques proved successful

   Divide and Conquer

   Dynamic Programming

   Greedy Approach

   Backtracking

   Local Search

 

      Compare alternate techniques to arrive at the best

Algorithm Development

      Algorithm precise and complete description of high level strategy

      The high level strategy, in general, sketchy and usable only by humans

      Many more details needed which are added in this phase

      Leads to a precise sequence of instructions

      Instructions specify the various data objects and operations

      The data objects are at a very high level closer to the problem domain

      Various constructs like sequencing, conditionals and looping are used to control the flow of execution of the instruction

Algorithm Analysis

      Algorithm analyzed for correctness and efficiency

      They are precise and detailed enough for these analysis

      Correctness analysis:

    to ensure the algorithm solves the given problem

    This involves a mathematical proof that algorithm satisfies the specification; termination proofs

      Efficiency analysis:

     to determine the amount of time or number of operations and amount of memory required for executing the algorithm

      This explores possible alternate designs of data and control structures to select the best possible one

Programming (coding algorithms)

       Writing programs in a programming language is the last step

 

       No doubt it is important and one need to pay attention and care

 

       But it is somewhat straightforward

 

       It requires mastery over the programming language

 

       This step is programming language dependent

 

       So in the development of a solution, only this step need to change for a different programming language

 

       This step is called implementation or coding

Testing the Program

      In this phase, the program is compiled to generate machine code that can run on a specific machine

      Errors could be introduced in the programming process or by the compiler

      Hence it is essential that the generated code is run with specific set of inputs to see whether it produces the right outputs

      Syntax errors eliminated in the step

      Some logical errors may also be caught in this step

      It also gives an idea about time and space requirements for executing the program

Problem Solving Strategies

 

       Arriving at a strategy and an algorithm is the most crucial and difficult step

       Crucial because behavior of the final code is dependent on this

       Difficult because it is a creative step

       Though many standard techniques are available no general recipe to ensure success

       New problems may require newer strategies

       Problem solving skills can be developed only with experience

       Main emphasis of the course: to expose you to various problem solving strategies by way of examples

       The programming languages is for concreteness and execution of your ideas

Illustrative Examples

      Problem: Given a set of students examination marks, (range 0 to 100), count the number of students that passed the      examination and those passed with distinction;

   pass mark: >=50, distinction mark: >=80

 

      Study the problem and analyze

 

      Is the problem definition clear?

The Strategy

 

        Keep two counters one for pass and the other for distinction

 

       Read the marks one by one

 

      compare each mark with 50 and 80 and increase the appropriate counters

 

       Print the final results

The algorithm

 

Algorithm pass_count:

Input: List of marks

Output: pass_count, distinction_count

 

1. initialize p_count, d_count to zero

2. Do while (there is next_mark) steps 2.1 and 2.2

            2.1 If next_mark => 50 then increment p_count

            2.2 If next_mark => 80 then increment d_count

end pass_count

Observations

      The algorithm is a sequence of precise instructions

 

     Involves variables for storing input, intermediate   and   output data

 

     uses high level operations and instructions

 

     Data types closer to the problem domain

 

      What does the algorithm do for marks that do not lie between 0 and 100 ?

 

      Rewrite the algorithm

Correctness of the Solution

      Is the solution correct?

      Show that

   if an input satisfies the input constraints

   then output produced satisfies required properties

 

      Input Constraints

   List of integers lying between 0 and 100

 

      Required Property

   p_count contains the no. of marks >= 50

   d_count contains the no. of marks >= 80

 

      Termination is an implicit requirement

 

 

 

How to establish correctness

      Establish that

           if  input constraint is satisfied then

           the program will terminate producing the

           output that satisfies the desired properties

      How to establish?

   Testing?

    How many inputs will convince you?

   5, 10, 100 in general infinite

Testing  establish presence of bugs never their absence

 

 

Mathematical Argument

      Prove the correctness using mathematical arguments

 

      Proof of Correctness involves two-Step argument

 

    Loop Invariants

    Loop Termination

 

 

Loop invariants

       A condition (logical expression) involving program variables

    It holds initially

    If it holds before start of iteration, it holds at the end;

    The condition remains invariant under iteration

 

       Loop invariant for our example

      p_count and d_count hold the total number of pass and distinction marks in the marks read so far 

 

       Loop invariants holds at every iteration if it holds initially

       In particular, it holds at the end

       Input constraints imply loop invariant initially

       Loop invariant at the end, implies output condition

Loop Termination

      Non termination is an important source of incorrectness.

      Correctness proof includes termination proof

      An integer valued expression called bound function that reduces in each iteration

      When the bound function reaches 0, loop terminates

      For our example, the bound function is:

        length of the input list yet to be processed

Efficiency Analysis

      How many number of operations?

 

   In each iteration of the loop, constant number of comparisons

 

      Can we improve this?

 

   If the number is less than 50, there is no need for comparing it with 80.

 

      Rewrite the algorithm

Encoding the algorithm

      How to implement the algorithm?

 

      More or less straightforward:

     counter variables are integer variables

     read and print statements

     the loop into a `do statement

      But wait!

     How to terminate the loop?

 

      We need to have a protocol for communication

     Input the total no. of marks

     Input a blank line or line with a special number

     What could be the special number?

Program pd_count

       implicit none

     integer, parameter:: p_mark = 50
integer, parameter:: d_mark = 80
integer:: p_count,d_count
integer:: N, mark, index
! N - the total number of marks to be processed
! mark - temporary variable to store the mark being processed
p_count = 0;
d_count = 0;
read *, N;
do index = 1, N
     read *, mark
     if (mark > = p_mark) then
        p_count = p_count + 1
        if (mark >= d_mark) then
            d_count = d_count +1
        endif
     endif
end do
print *, p_count,d_count

Some Observations

      Note the use of constant identifiers p_mark and d_mark rather than actual values 50, 80. This is preferable when the pass mark or distinction marks change.

      variables and constants have meaningful names conveying the intent. Programs need to be maintained. Human understanding is essential

      All variables need to be  initialized

      Always use implicit none to catch typographical errors

Testing

       Finally Compile the program and test

 

       Why test? We have already verified!

 

       What inputs should be given?

 

       Inputs that exercise boundary conditions

 

      Total Number of marks: 0, 1

      Actual Marks: 49, 50, 51, 79, 80, 81

 

       Representative Inputs:

 

      Total Number of inputs: 0, 25, 100

      Actual Marks:  -34, 0, 25, 67, 92, 120