Team project: C or C++ Explainer-like rating program

Programs which generate, solve, and analyze Sudoku puzzles

Re: Team project: C or C++ Explainer-like rating program

Postby champagne » Mon Oct 18, 2010 11:23 am

ronk wrote:
PIsaacson wrote:I'm nowhere near finished designing/coding, and with my current non-sudoku/programming activities I have no idea how long it will take to complete. This was supposed to be a team effort, but nobody volunteered to be the team leader, so I got impatient and starting assembling stuff I had previously used in various test projects.

Which Sudoku techniques have you included so far? Of those, which yield ER scores identical to Explainer?

I've been patiently waiting for someone to publish a "framework", a "starter program" with basic techniques, so that others might add higher level techniques in parallel. If you plan on "finishing designing/coding", what roles are left for others?



It's not so easy to open the door to anybody willing to add code when you start from scratch using your own code;

I am back on that topic since the last pattern game was closed.

I have now a framework including the code and options I consider as usefull for a player in the pattern game,up to all bug patterns.

Next steps

. aligned pairs (6.2),
. X cycles (6.5)
. X forcing chains (6.6 6.7)

should be easy to handle thru my tagging process.

After I don't know, I have to see what SE is doing.

I had to change my code for UE, UL and BUGs, so I have some tests to do to validate that part and see if it matchs with SE.

Options are more or less what I described earlier. I just added a second output file to split rated and non rated puzzles when a filter is used.

I am open to post existing code anywhere, but the reader must be prepared to find some comments in frenh or in a poor english.

I switched recently ot he platform visual c++ 2010 with no GUI

champagne
champagne
2017 Supporter
 
Posts: 7455
Joined: 02 August 2007
Location: France Brittany

Re: Team project: C or C++ Explainer-like rating program

Postby lksudoku » Mon Oct 18, 2010 12:56 pm

champagne wrote:I had to change my code for UE, UL and BUGs, so I have some tests to do to validate that part and see if it matchs with SE.

Current SE has a bug in the UL/UR code causing it not to find some UL that exist

I have created a fixed version of SE that should find all UL/UR

You can download the fixed jar file from
http://sites.google.com/site/sefixshare/files/FIXED1SudokuExplainer.jar

I suggest all UL analysis will be done with this fixed version

Also note, that in some cases finding one UR first may destroy another UR thus the UR identification order may change the rating as seen in the bugs topic
lksudoku
 
Posts: 90
Joined: 06 October 2010

Re: Team project: C or C++ Explainer-like rating program

Postby champagne » Mon Oct 18, 2010 1:25 pm

lksudoku wrote:
champagne wrote:I had to change my code for UE, UL and BUGs, so I have some tests to do to validate that part and see if it matchs with SE.

Current SE has a bug in the UL/UR code causing it not to find some UL that exist

I have created a fixed version of SE that should find all UL/UR

You can download the fixed jar file from
http://sites.google.com/site/sefixshare/files/FIXED1SudokuExplainer.jar

I suggest all UL analysis will be done with this fixed version

Also note, that in some cases finding one UR first may destroy another UR thus the UR identification order may change the rating as seen in the bugs topic


thanks for the concept of a fixed version of SE.

For the time being, nobody is prepared to change the rating tool for SE.

I guess this can change if we come to an alternate program matching say 99.99% of the past results of SE in the pattern game and solving most of identified bugs.

At that point, your findings can be valued. In my case, the most useful would be to get a sample file of puzzles where this exists and changes the rating.

Regarding the order in which UR are taken, this is a known problem. I hope it will stay within the 0.01% of "non match". I'll try anyway to stick to SE sequence.

In case we would not succeed in creating the alternate SE rating, I'll have at the end a much better performing program to "approach" SE rating. In a game like game 122, this is unvaluable. (open to anybody willing to use it)

champagne
champagne
2017 Supporter
 
Posts: 7455
Joined: 02 August 2007
Location: France Brittany

Re: Team project: C or C++ Explainer-like rating program

Postby ronk » Mon Oct 18, 2010 3:48 pm

lksudoku wrote:I have created a fixed version of SE that should find all UL/UR

You can download the fixed jar file from
http://sites.google.com/site/sefixshare/files/FIXED1SudokuExplainer.jar

I suggest all UL analysis will be done with this fixed version

Thanks for posting that. The GUI version number ... 1.2.1 ... is unchanged. It didn't get changed in the recent past either, but it's probably time to start.
ronk
2012 Supporter
 
Posts: 4764
Joined: 02 November 2005
Location: Southeastern USA

Re: Team project: C or C++ Explainer-like rating program

Postby lksudoku » Mon Oct 18, 2010 4:37 pm

ronk wrote:The GUI version number ... 1.2.1 ... is unchanged. It didn't get changed in the recent past either, but it's probably time to start.

I have now updated the version number of the posted fixed version
GUI version number changed to 1.2.2.0
command line serate version number also changed to 1.2.2.0
lksudoku
 
Posts: 90
Joined: 06 October 2010

re: Direct Hidden Pair

Postby Pat » Tue Oct 19, 2010 8:21 am

PIsaacson wrote:Here's a list of all the methods I have currently debugged and operational.
The scoring of each method matches SE as closely as possible---
  • ...
  • direct_hidden_pair.cpp
  • ...


as far as i recall from the earlier discussion,
your definition of "Direct Hidden Pair" differs from the definition used in Sudoku Explainer
-- or am i misunderstanding you?
User avatar
Pat
 
Posts: 4056
Joined: 18 July 2005

Re: Team project: C or C++ Explainer-like rating program

Postby PIsaacson » Tue Oct 19, 2010 10:09 am

Pat,

My implementation of APE and ATE, in addition to the standard bi-value excluders, also uses exclusion sets consisting of ALSs: 2 cell/3 candidate box constrained ALSs for aligned pairs and 3 cell/4 candidate box constrained ALSs for aligned triples. This is based on the work presented elsewhere on the Type 2 APEs: http://www.sudokuwiki.org/Aligned_Pair_Exclusion

Let me assert yet again that I am no longer trying to perfectly duplicate SE. I don't think that's the right approach and it seems like a step backwards considering that we now have better knowledge and techniques at our disposal. As an example, SE doesn't have any ALS sets/chains processing, yet they produce some of the more interesting rank-0 patterns that crack really hard puzzles. Okay, I admit to having a fondness for all things ALS'ish, but why not code something that contains current advanced techniques? That said, I am in the final stages of coding the SE recursive forcing chains stuff for all the really tough problems, but I'd rather be coding a fast SK loop engine, or working with Champagne on his Bi-Bi logic, or replicating Allan's Ribbons...

Cheers,
Paul
PIsaacson
 
Posts: 249
Joined: 02 July 2008

Re: Team project: C or C++ Explainer-like rating program

Postby ronk » Tue Oct 19, 2010 12:10 pm

PIsaacson wrote:Let me assert yet again that I am no longer trying to perfectly duplicate SE. I don't think that's the right approach and it seems like a step backward considering that we now have better knowledge and techniques at our disposal. As an example, SE doesn't have any ALS sets/chains processing, yet they produce some of the more interesting rank-0 patterns that crack really hard puzzles.

On the one hand, with "perfect ratings duplication" of SE as a goal, at least the project had a well-defined goal. OTOH since you've posted 99%+ of the coding results, I suppose a well-defined goal is not actually required. Without such a goal, however, I withdraw from this project and retire to the peanut gallery.

JasonLion, if technically practical and if someone requests, you may re-assign ownership of my opening post in this thread as you see fit. It really doesn't say anything of note anyway.
ronk
2012 Supporter
 
Posts: 4764
Joined: 02 November 2005
Location: Southeastern USA

Re: Team project: C or C++ Explainer-like rating program

Postby champagne » Tue Oct 19, 2010 1:25 pm

ronk wrote:
PIsaacson wrote:Let me assert yet again that I am no longer trying to perfectly duplicate SE. I don't think that's the right approach and it seems like a step backward considering that we now have better knowledge and techniques at our disposal. As an example, SE doesn't have any ALS sets/chains processing, yet they produce some of the more interesting rank-0 patterns that crack really hard puzzles.

On the one hand, with "perfect ratings duplication" of SE as a goal, at least the project had a well-defined goal. OTOH since you've posted 99%+ of the coding results, I suppose a well-defined goal is not actually required. Without such a goal, however, I withdraw from this project and retire to the peanut gallery.

JasonLion-admin, if technically practical and if someone requests, you may re-assign ownership of my opening post in this thread as you see fit. It really doesn't say anything of note anyway.


I am somehow surprised with such a strong reaction.

Paul' POV can be understood. Paul never participated to the pattern game and I must confess that, if the work is not done to ease the task of pattern game players, i see no reason to stick to SE specifications.


For sure,

SE is the oldest shared rating program,
SE rates all puzzles and, if the correlation remains poor, the rating tendency is very similar to others.


This is not enough to be forced to limit the solver to the technics used in SE.

As I am one of players in the pattern game, I have a different view and i stick to my attempt to clone SE.

If I understand, I am the last one working on that topic :D

I was thinking of posting slowly the code of my clone here in case anybody would contribute to debugging and optimisation of it, it seems of "no interest".

champagne
champagne
2017 Supporter
 
Posts: 7455
Joined: 02 August 2007
Location: France Brittany

Re: Team project: C or C++ Explainer-like rating program

Postby BryanL » Tue Oct 19, 2010 1:44 pm

ronk wrote:
PIsaacson wrote:Let me assert yet again that I am no longer trying to perfectly duplicate SE. I don't think that's the right approach and it seems like a step backward considering that we now have better knowledge and techniques at our disposal. As an example, SE doesn't have any ALS sets/chains processing, yet they produce some of the more interesting rank-0 patterns that crack really hard puzzles.

On the one hand, with "perfect ratings duplication" of SE as a goal, at least the project had a well-defined goal. OTOH since you've posted 99%+ of the coding results, I suppose a well-defined goal is not actually required. Without such a goal, however, I withdraw from this project and retire to the peanut gallery.

JasonLion, if technically practical and if someone requests, you may re-assign ownership of my opening post in this thread as you see fit. It really doesn't say anything of note anyway.


Man that blows me away...

It has been stated repeatedly that it wouldn't be possible to mimic SE's rating unless the bugs were deliberately left in. Why do that? And as Paul says, techniques have been refined - why not implement them?

Paul and lksudoku have done the hard yards that no-one else has been prepared (or capable enough) to do. Give them a cigar... :)

We are close to the primary goal of a faster rating solver. And for those that want vanilla C, that will be easy.

Great effort guys...
BryanL
 
Posts: 247
Joined: 28 September 2010

Re: Team project: C or C++ Explainer-like rating program

Postby BryanL » Tue Oct 19, 2010 1:51 pm

champagne wrote:
As I am one of players in the pattern game, I have a different view and i stick to my attempt to clone SE.

If I understand, I am the last one working on that topic :D

I was thinking of posting slowly the code of my clone here in case anybody would contribute to debugging and optimisation of it, it seems of "no interest".

champagne


Maybe now is the time to start a thread or two on the programmer's forum - anywhere for all I care - where there can be some peer review with a view to optimisation and debugging.

I am certainly interested and am sure there would be plenty who would also.
BryanL
 
Posts: 247
Joined: 28 September 2010

Re: Team project: C or C++ Explainer-like rating program

Postby champagne » Tue Oct 19, 2010 2:31 pm

BryanL wrote:Maybe now is the time to start a thread or two on the programmer's forum - anywhere for all I care - where there can be some peer review with a view to optimisation and debugging.

I am certainly interested and am sure there would be plenty who would also.



ok if your views are shared, I will open very quickly a thread dedicated to that clone.


I am working with the pattern game results as test file.
For the upper levels (11.xx) I 'll extract the necessary stuff from my database.

I am currently re rating the pattern game results with the option "elapsed time" to have a basis for a benchmark.


So far, i have the code to run the programm till the rating level 6.1 and I am testing rating levels 4.5/4.6
I got 100% match below 4.5 with the test file.

I intend to disclose the code in the following way:

- command line and options (the easiest point to discuss)
- main routine and files management
- general classes used to handle basic properties
- all necessary code to check uniqueness
- sequence control and options handling
- step by step the code for each rating level, with necessary specific classes.

I'll do it in parallel with other tasks, so it could be a relatively slow process.

It would be good to have the possibility to have 2 threads, one open to discussions, one kept sane to keep an updated version of the code.

I don't know how this can be done.

champagne
champagne
2017 Supporter
 
Posts: 7455
Joined: 02 August 2007
Location: France Brittany

Re: Team project: C or C++ Explainer-like rating program

Postby PIsaacson » Tue Oct 19, 2010 7:50 pm

Ron,

Don't abandon all hope yet. After all, I did say
Code: Select all
That said, I am in the final stages of coding the SE recursive forcing chains stuff for all the really tough problems...

BUT... I'm really having problems trying to exactly match SE on even simple stuff like the following:
Code: Select all
023000000450000000000100060007800000000000200000000450000024000608000000000000307

 1789      2         3        |45679     456789    56789    |15789     14789     14589   
 4         5         169      |23679     36789     236789   |1789      123789    12389   
 789       789       9        |1         345789    235789   |5789      6         234589   
 --------- --------- ---------+--------- --------- ---------+--------- --------- ---------
 12359     13469     7        |8         134569    123569   |169       139       1369     
 13589     134689    14569    |345679    1345679   135679   |2         13789     13689   
 12389     13689     1269     |23679     13679     123679   |4         5         13689   
 --------- --------- ---------+--------- --------- ---------+--------- --------- ---------
 13579     1379      159      |35679     2         4        |15689     189       15689   
 6         13479     8        |3579      13579     13579    |159       1249      12459   
 1259      149       12459    |569       15689     15689    |3         12489     7       

  1)  1.2 r2c3 <= 6 hidden single in b1
  2)  1.2 r1c1 <= 1 hidden single in b1
  3)  1.2 r5c8 <= 7 hidden single in b6
  4)  2.0 r3c3 <= 9    direct hidden pair b1x78.<78>
  5)  2.5 r3c7 <= 5    direct hidden triple r3c69.<234>
  6)  2.6 r3c5 <> 7 locked candidates type 1 (pointing) b1/r3
  7)  2.6 r3c6 <> 7 locked candidates type 1 (pointing) b1/r3
  8)  2.6 r3c5 <> 8 locked candidates type 1 (pointing) b1/r3
  9)  2.6 r3c6 <> 8 locked candidates type 1 (pointing) b1/r3
 10)  2.6 r3c9 <> 8 locked candidates type 1 (pointing) b1/r3
 11)  2.6 r1c9 <> 8 locked candidates type 1 (pointing) b6/c9
 12)  2.6 r2c9 <> 8 locked candidates type 1 (pointing) b6/c9
 13)  2.6 r7c9 <> 8 locked candidates type 1 (pointing) b6/c9
 14)  2.6 r9c8 <> 2 locked candidates type 1 (pointing) b7/r9
 15)  2.6 r9c8 <> 8 locked candidates type 1 (pointing) b8/r9
 16)  2.6 r7c4 <> 6 locked candidates type 1 (pointing) b9/r7
 17)  7.0 r9c1 <> 5 xy-cycle[6]-chain [r9c1]=2=[r9c3]-2-[r6c3]=2=[r6c3]-1-[r7c3]=1=[r7c3]-5
 18)  7.1 r5c5 <> 4 xy-cycle[10]-chain [r5c3]=4=[r9c3]-4-[r9c3]=2=[r9c1]-2-[r4c1]=2=[r4c6]-2-[r3c6]=2=[r3c6]-3-[r3c5]=3=[r3c5]-4
 19)  7.1 r2c4 <> 3 xy-cycle[10]-chain [r2c4]=2=[r6c4]-2-[r6c3]=2=[r9c3]-2-[r9c3]=4=[r5c3]-4-[r5c4]=4=[r4c5]-4-[r3c5]=4=[r3c5]-3
 20)  7.1 r8c9 <> 2 xy-cycle[10]-chain [r8c8]=2=[r2c8]-2-[r2c4]=2=[r6c4]-2-[r6c3]=2=[r6c3]-1-[r7c3]=1=[r7c3]-5-[r7c9]=5=[r8c9]-5
 21)  1.2 r8c8 <= 2 hidden single in b9
 22)  3.8 r5c2 <> 4 swordfish r348\c259
 23)  3.8 r9c2 <> 4 swordfish r348\c259
 24)  3.8 r1c5 <> 4 swordfish r348\c259
 25)  3.8 r1c9 <> 4 swordfish r348\c259
 26)  2.3 r1c9 <= 9 naked single
 27)  2.6 r4c1 <> 9 locked candidates type 1 (pointing) b6/r4
 28)  2.6 r4c2 <> 9 locked candidates type 1 (pointing) b6/r4
 29)  2.6 r4c5 <> 9 locked candidates type 1 (pointing) b6/r4
 30)  2.6 r4c6 <> 9 locked candidates type 1 (pointing) b6/r4
 31)  7.0 r7c8 <> 9 xy-cycle[6]-chain [r7c8]=8=[r7c7]-8-[r7c7]=6=[r4c7]-6-[r4c7]=9=[r4c8]-9
 32)  7.0 r7c9 <> 1 xy-cycle[8]-chain [r7c8]=1=[r7c8]-8-[r1c8]=8=[r1c8]-4-[r9c8]=4=[r8c9]-4-[r8c9]=5=[r7c9]-5
 33)  7.0 r8c2 <> 1 xy-cycle[6]-chain [r8c2]=4=[r8c9]-4-[r8c9]=5=[r7c9]-5-[r7c3]=5=[r7c3]-1
 34)  7.0 r8c2 <> 9 xy-cycle[8]-chain [r8c2]=4=[r8c9]-4-[r8c9]=5=[r7c9]-5-[r7c3]=5=[r7c3]-1-[r9c2]=1=[r9c2]-9
 35)  7.0 r5c3 <> 1 xy-cycle[8]-chain [r5c3]=4=[r9c3]-4-[r8c2]=4=[r8c9]-4-[r8c9]=5=[r7c9]-5-[r7c3]=5=[r7c3]-1
 36)  7.0 r8c9 <> 1 xy-cycle[6]-chain [r7c8]=1=[r7c8]-8-[r1c8]=8=[r1c8]-4-[r9c8]=4=[r8c9]-4
 37)  7.0 r4c2 <> 6 xy-cycle[8]-chain [r4c7]=6=[r7c7]-6-[r7c9]=6=[r7c9]-5-[r8c9]=5=[r8c9]-4-[r8c2]=4=[r4c2]-4
 38)  7.0 r2c8 <> 8 xy-cycle[8]-chain [r7c8]=8=[r7c7]-8-[r7c7]=6=[r4c7]-6-[r4c7]=9=[r4c8]-9-[r4c8]=3=[r2c8]-3
 39)  7.0 r9c3 <> 5 xy-cycle[8]-chain [r9c3]=4=[r9c8]-4-[r1c8]=4=[r1c8]-8-[r7c8]=8=[r7c8]-1-[r7c3]=1=[r7c3]-5
 40)  1.7 r8c9 <= 5 direct pointing b7/r7
 41)  1.2 r9c8 <= 4 hidden single in b9
 42)  1.2 r3c9 <= 4 hidden single in b3
 43)  1.2 r1c4 <= 4 hidden single in b2
 44)  1.2 r2c9 <= 2 hidden single in b3
 45)  1.2 r3c6 <= 2 hidden single in b2
 46)  1.2 r2c8 <= 3 hidden single in b3
 47)  1.2 r3c5 <= 3 hidden single in b2
 48)  1.2 r2c7 <= 1 hidden single in b3
 49)  1.2 r1c7 <= 7 hidden single in b3
 50)  1.0 r1c8 <= 8 full house in b3
 51)  1.2 r6c4 <= 2 hidden single in b5
 52)  1.2 r4c1 <= 2 hidden single in b4
 53)  1.2 r4c5 <= 4 hidden single in b5
 54)  1.2 r5c3 <= 4 hidden single in b4
 55)  1.2 r5c1 <= 5 hidden single in b4
 56)  1.2 r4c6 <= 5 hidden single in b5
 57)  1.2 r1c5 <= 5 hidden single in b2
 58)  1.0 r1c6 <= 6 full house in r1
 59)  1.2 r9c3 <= 2 hidden single in b7
 60)  1.2 r8c2 <= 4 hidden single in b7
 61)  1.2 r7c3 <= 5 hidden single in b7
 62)  1.0 r6c3 <= 1 full house in c3
 63)  1.2 r9c4 <= 5 hidden single in b8
 64)  1.2 r9c5 <= 6 hidden single in b8
 65)  1.2 r5c4 <= 6 hidden single in b5
 66)  1.2 r6c2 <= 6 hidden single in b4
 67)  1.2 r9c6 <= 8 hidden single in b8
 68)  1.2 r2c5 <= 8 hidden single in b2
 69)  1.2 r7c8 <= 1 hidden single in b9
 70)  1.0 r4c8 <= 9 full house in c8
 71)  1.2 r9c2 <= 1 hidden single in b7
 72)  1.0 r9c1 <= 9 full house in r9
 73)  1.2 r5c2 <= 9 hidden single in b4
 74)  1.2 r6c1 <= 8 hidden single in b4
 75)  1.0 r4c2 <= 3 full house in b4
 76)  1.2 r3c2 <= 8 hidden single in b1
 77)  1.0 r3c1 <= 7 full house in b1
 78)  1.0 r7c1 <= 3 full house in c1
 79)  1.0 r7c2 <= 7 full house in c2
 80)  1.2 r5c9 <= 8 hidden single in b6
 81)  1.2 r4c9 <= 1 hidden single in b6
 82)  1.0 r4c7 <= 6 full house in r4
 83)  1.0 r6c9 <= 3 full house in b6
 84)  1.0 r7c9 <= 6 full house in c9
 85)  1.2 r5c6 <= 3 hidden single in b5
 86)  1.0 r5c5 <= 1 full house in r5
 87)  1.2 r8c6 <= 1 hidden single in b8
 88)  1.2 r8c4 <= 3 hidden single in b8
 89)  1.2 r8c5 <= 7 hidden single in b8
 90)  1.0 r6c5 <= 9 full house in c5
 91)  1.0 r6c6 <= 7 full house in b5
 92)  1.0 r2c6 <= 9 full house in c6
 93)  1.0 r2c4 <= 7 full house in r2
 94)  1.0 r7c4 <= 9 full house in c4
 95)  1.0 r7c7 <= 8 full house in r7
 96)  1.0 r8c7 <= 9 full house in c7
.23......45..........1...6...78...........2........45.....24...6.8............3.7 1 7.1 1.2 1.2 161.5726ms

Run the same puzzle in SE and step until you hit the 7.3 bi-directional cycle (xy-cycle loop). Count the number of links - it's 12!!! I found several shorter/simpler standard discontinuous nice-loops (xy-cycle chain) length 10 which keeps my score to 7.1. Now, I'll admit that I'm having problems with the chain length score adjustments, but the length of a chain is pretty easy to count. Just another example of the SE anomalies that I'm tracking down...

I'm still waiting for all those PMs saying that you just can't wait to get your hands on my code...

Cheers,
Paul
PIsaacson
 
Posts: 249
Joined: 02 July 2008

Re: Team project: C or C++ Explainer-like rating program

Postby ronk » Tue Oct 19, 2010 9:04 pm

PIsaacson wrote:Run the same puzzle in SE and step until you hit the 7.3 bi-directional cycle (xy-cycle loop). Count the number of links - it's 12!!! I found several shorter/simpler standard discontinuous nice-loops (xy-cycle chain) length 10 which keeps my score to 7.1. Now, I'll admit that I'm having problems with the chain length score adjustments, but the length of a chain is pretty easy to count. Just another example of the SE anomalies that I'm tracking down...

[edit: For chains with one or more bilocal strong links], I think a discontinuous nice loop with N strong links scores the same as a continuous nice loop with N+1 strong links. Probably only Nicolas Juillerat knows why.
Last edited by ronk on Wed Oct 20, 2010 11:19 am, edited 1 time in total.
ronk
2012 Supporter
 
Posts: 4764
Joined: 02 November 2005
Location: Southeastern USA

Re: Team project: C or C++ Explainer-like rating program

Postby JasonLion » Tue Oct 19, 2010 11:27 pm

champagne wrote:I intend to disclose the code in the following way:

- command line and options (the easiest point to discuss)
- main routine and files management
- general classes used to handle basic properties
- all necessary code to check uniqueness
- sequence control and options handling
- step by step the code for each rating level, with necessary specific classes.

I'll do it in parallel with other tasks, so it could be a relatively slow process.

My personal interest is in optimization. Optimization doesn't normally respect the existing structure of the code. You run a profiler, find problem areas, and do whatever is needed to make that code faster; regardless of what section(s) of the code that involves. In many cases this ends up involving significant restructuring of the code.
User avatar
JasonLion
2017 Supporter
 
Posts: 642
Joined: 25 October 2007
Location: Silver Spring, MD, USA

PreviousNext

Return to Software