devel: How does it work?

details for developers

This section describes in detail how some things work in practice. Although it is provided here for developers, it does not present any source code; rather it describes some key ideas of this program. Therefore it may be interesting for common users too.

You will find here descriptions of

Q: speed goals
Q: wise random draws
Q: first run
Q: forced scheduling

Q: speed goals

A: The task of speed goals in KLearnNotes2 is too ecurage training for speed.

There are two factors which influence speed goal:

your level

i.e. whether you define yourself a Prentice/a Journeyman or a Wizard; by changing level you can setup higher speed goals as you advance

number of active namebuttons

it is physically more difficult to find a right button with your mouse if there are many of them active; threfore for exercises with higher number of active namebuttons speed goals are lower

In each case there are speed goals for 2 and 7 active namebuttons specified. Based on these speed goals for other active namebuttons numbers are interpolated.

  • for a Prentice speed goals vary from 100 answ/(10 min) for 2 active namebuttons to 80 answ/(10 min) for 7 namebuttons

  • for a Prentice from 300 answ/(10 min) to 200 answ/(10 min)

  • for a Wizard from 500 answ/(10 min) to 300 answ/(10 min)

This means, that differences between different levels are smaller for big number of active namebuttons. This is because how much speed you loose because of more buttons depends on your clicking skills rather than your notes recognition skills, and therefore should not be reflected in levels.

You may setup your own speed goal progress ("a custom level"). You simply select a speed goal for 2 active namebuttons and for 7 active namebuttons. These values are linearly interpolated for intermediate numbers of active namebuttons.

Your last custom speeds are remembered even if you choose one of the preset levels. You may easily come back to them by selecting "custom" again.

Final remark: it is also more difficult to answer fast if there are more notes active. E.g. Exercise 01 is more difficult then Exercise 31: in both cases there are only "C" and "G" notes, but there are much more testnotes in the latter exercise. But there is no reason to reflect this difficulty in speed goal - this is exactly what you are training for: train until you get a good notes recognition speed for big number of notes! Progression in speed goal was introduced to account for clicking difficulty, not for note-recognition difficulty!

Q: wise random draws

A: In KLearnNotes2 questions are not totally random. Rather, they are chosen in such a way, that notes difficult for the student appear more frequently.

In the following description number of testnotes (notes active in a particular test) is denoted by N.

  1. each note has a weight W assigned according to the formula:

    where OK is number of right answers about this note, WR is number of wrong answers about this note, and speed is calculated according to the formula:

    that is: total number of answers about this note divided by time spent on these answers.

    This means, that:

    • each wrong answer multiply W by 5; this makes this note more probable in futures

    • each right answer multiply W by 0.75; this is done to promote diversity of questions (once a note is asked about and the answer is right, this note is less probable for future)

    • if user answers fast about a note this note gets less probable in future;

      (note, that it is not very probable that in normal usage speeds may differ by a factor 5; therefore even fast wrong answers make the note MORE probable for future); (but I consider changing the formula of speed to OK/time - giving a wrong answer would additionally slow "speed" down and increase W)

    • if user answers slowly about a note this note gets more probable in future;

  2. a range (0,10000) is divided into N parts of lengths proportional to the weights W of testnotes

  3. an integer number in range (0,10000) is selected at random; new question will be about the note to which part this number belongs to.

Example: Let us assume, that there are 3 testnotes: C, D, E.

Altogether, the region (0...10000) will be split in ratio 0.28 : 0.75 : 10 ; if we got a random number in region There is a 'but'. To make exercise more diverse program secures, that the same note would not be repeated as a result of this random draw (note, that it can be repeated as a result of force-scheduling!). Therefore, in above situation:

  • if last note was C, the only notes possible for next question are E and D, and E is 13 times more probable (13 = 10 : 0.75)

  • if last note was D, the only notes possible for next question are E and C, and E is 35 times more probable (35 = 10 : 0.28)

  • if last note was E, the only notes possible for next question are C and D, and D is 2.7 times more probable (2.7 = 0.75 : 0.28)

Q: first run

A: Each TEST starts from a series of questions about all the testnotes (in random order, but without possibility of being repeated). Example: In Exercise 01 there are four testnotes: 'C','G','C1' and 'G1'. First few questions in an Exercise 01 test could look like this:

C  - C1 - G  - G1 - C1 - G1 - C1 - G1 - C  - G ...
C1 - C  - G  - G1 - C  - G  - C1 - G1 - C1 - G ...
G  - C1 - G1 - C  - C1 - G1 - C  - G  - C  - G ...
- in first four question no note gets repeated (which also means, that all notes are asked before real random draw starts at question number 5).

Q: forced scheduling

A: This program uses an array of forced-scheduled questions. It keeps references to notes which obligatorily should be asked about in future.

If you want to see how forced-schedule array looks like, uncomment (delete //) 20th line of klearnnotes.h file: #define _KLN_SHOW_SCHEDULE I will use below example output (from stderr) generated after defining this option for Exercise01.

In the beginning of each TEST, forced-schedule array is generated.

DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (G12,*) (C16, ) ( G5, ) ( C9, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING THE SCHEDULED NOTE
First line just informs, that forced-schedule array keeps maximum of 30 notes (MAXseria=40). There is no much point in scheduling questions more than 30 questions ahead. On the other hand, some exercises, like Exe. 40 eat up as much as 23 slots for the first run, and that's why I didn't want to assign to MAXseria a number less than 30.

Then, noOfTestnotes=4 informs you, that there are 4 testnotes, which is true for Exercise 01.

Then real force-schedule array follows. Current question is marked by a star (*).

  • If there was no forced-scheduled note for this question you will see ( X* ), and a comment DEBUG: USING A RANDOM NOTE below.

  • If there was a forced-scheduled note for this question you will see (NOTENAME,NOTENUMBER*), and a comment DEBUG: USING THE SCHEDULED NOTE below.

    Note, that NOTENUMBER is calculated as a number of a note, counting ALL notes (and not testnotes only) from the TOP. Therefore (G5,) in above example is the highest note (i.e. 'G1'), then comes (C9,) (i.e. 'C1'), (G12,) (i.e. 2nd_line-G) and finally (C16,) (i.e. middle-C).

Note, that I use question number (modulo 30) as this array index. Therefore the first question is ... the second in the first row. ;)

You see above, that the first question and three next are already scheduled due to first-run forced-scheduling described above. After answering first question right ('G') we go to the second question:

scheduled notes:
 (  X, ) (  X, ) (C16,*) ( G5, ) ( C9, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING THE SCHEDULED NOTE
You see, that the schedule at position 1 was reset to (X). This is because the array will be reused: after reaching question number 29 we go to the beginning of the array (again: as index, question number modulo 30 is used).

After answering C-G-C to next questions one gets:

DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) ( G5,*) ( C9, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING THE SCHEDULED NOTE
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) ( C9,*) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING THE SCHEDULED NOTE
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X,*) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING A RANDOM NOTE
Now, here we have eventually got out of the first run, and this is first randomly generated question (DEBUG: USING A RANDOM NOTE). If you keep answering correct all you see is the star moving right, to next questions. At question 15 output will look like this:
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X,*) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING A RANDOM NOTE
Now, let's make a mistake. In my case, this question 15 was about the middle-C note. So, I clicked on 'G':
DEBUG: DONE UPDATING SCHEDULE TABLE; it is now:
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X,*) (  X, ) (C16, ) (  X, ) (  X, )
 (C16, ) (  X, ) (  X, ) (C16, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
the question number didn't change yet (do you see where the star is?), but two, five and eight questions ahead (C16, ) was scheduled. Next question is still chosen randomly:
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X,*) (C16, ) (  X, ) (  X, )
 (C16, ) (  X, ) (  X, ) (C16, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING A RANDOM NOTE
but the next one uses this schedule array:
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (C16,*) (  X, ) (  X, )
 (C16, ) (  X, ) (  X, ) (C16, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING THE SCHEDULED NOTE
and so on.

Now, let's answer all questions right until the question number 21:

DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X,*) (  X, ) (C16, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING A RANDOM NOTE
In my case it was a question about the 2nd-line G ; I decided to make a mistake and clicked 'C'. What should happen now is scheduling (G12,) 2, 5 and 8 notes ahead. But two notes ahead there is already (C16,) scheduled. Therefore the first scheduled note will come to the next available slot, just after (C16,), and next in predefined steps (+3,+3), which means, that (G12,) will in fact be scheduled 3,6 and 9 notes ahead:
DEBUG: DONE UPDATING SCHEDULE TABLE; it is now:
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (G12, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
 (  X, ) (  X,*) (  X, ) (C16, ) (G12, ) (  X, ) (  X, ) (G12, ) (  X, ) (  X, )
If 6 questions ahead there would be also an already taken slot, program would try to schedule this note 3,7 and 10 notes ahead, and so on. Note, that the array gets "wrapped" - last note was put into slot number 0 (which will be used for question number 30).

Now, I kept giving wrong answers. At question 30 force-scheduled array looked like this


DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (G12,*) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, )
 (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, )
 (C16, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, ) (  X, )
DEBUG: USING THE SCHEDULED NOTE
and at question 33

DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (  X, ) (  X, ) (  X, ) (G12,*) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, )
 (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, )
 (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, )
DEBUG: USING THE SCHEDULED NOTE
If I make a mistake this time, the first available slot will be slot number 0, and next (+3,+3) would wrap over and will not be scheduled at all.

DEBUG: DONE UPDATING SCHEDULE TABLE; it is now:
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (G12, ) (  X, ) (  X, ) (  X,*) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, )
 (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, )
 (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, )
DEBUG: MAXseria=30 noOfTestnotes=4 
scheduled notes: 
 (G12, ) (  X, ) (  X, ) (  X, ) (C16,*) (C16, ) (G12, ) (C16, ) (C16, ) (G12, )
 (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, )
 (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, ) (G12, ) (C16, ) (C16, )
DEBUG: USING THE SCHEDULED NOTE