Home. 
.

transparent

transparent

transparent

Altova Mailing List Archives


Re: [xsl] Sudoku solver - complete

From: "Dimitre Novatchev" <dnovatchev@--------->
To:
Date: 5/2/2006 4:00:00 PM
Wow...



Congratulations to Andrew for doing a fantastic speedup.



I will use this occasion to give you my latest two solutions
(sudoku4.xsl and sudoku5.xsl). From these the latter is a little bit
more sophisticated and works slightly faster when solving very
difficult boards.

My comparisons of Andrew's latest solution vs the two I provide below,
shows that there are cases where Andrew's solution outperforms mine up
to 4-5 times, other cases where they have the same time and still
other, where the two solutions below are 2-3 times faster.

Clearly, this is a valuable result, because it shows that both
Andrew's and mine sudoku solutions have a significant space for
improvement.

Therefore, wait for the next generation... :o)



I think that at this moment we have already improved our speed
hundreds of times.

Here are my two sudoku solvers:



sudoku4.xsl:
=========
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f xs">

<xsl:import href="func-apply.xsl"/>



<xsl:output omit-xml-declaration="yes" indent="yes"/>



<xsl:template match="/">



 <xsl:variable name="vFixed" select="f:cellsGroup('Fixed', /*/*)"/>
 <xsl:variable name="vEmpty" select="f:cellsGroup('Empty', /*/*)"/>

 <xsl:variable name="vallFillers" as="element()*">
	  <xsl:for-each select=
	   "f:makeFillers(f:cellsGroup('Fixed', /*/*), f:cellsGroup('Empty',
/*/*))">
	    <xsl:sort select="@row"/>
	    <xsl:sort select="@col"/>

	    <xsl:sequence select="."/>
	  </xsl:for-each>
 </xsl:variable>

  <xsl:sequence
    select="f:sudoku($vFixed, $vEmpty, $vallFillers)"/>
</xsl:template>

<xsl:variable name="vAllVals" select="1 to 9" as="xs:integer+"/>



<xsl:function name="f:cellsGroup" as="element()*">
  <xsl:param name="pgrpType" as="xs:string"/>
  <xsl:param name="pRows" as="element()*"/>
    <xsl:sequence select=
     "for $i in 1 to count($pRows),
           $vRow in $pRows[$i],
               $vNum in tokenize($vRow, ',')
                          [if($pgrpType='Fixed')
                              then . ne '0'
                              else . eq '0'
                          ][if($pgrpType='Empty')
                              then 1
                              else true()],
               $k in index-of(tokenize($vRow, ','),$vNum)
              return
                f:makeCell($i,$k, xs:integer($vNum))
     "/>
</xsl:function>

<xsl:function name="f:makeCell" as="element()">
 <xsl:param name="pnRow" as="xs:integer"/>
 <xsl:param name="pnCol" as="xs:integer"/>
 <xsl:param name="pnVal" as="xs:integer"/>

 <cell row="{$pnRow}" col="{$pnCol}" val="{$pnVal}"/>
</xsl:function>

<xsl:function name="f:sudoku" as="item()*">
  <xsl:param name="pFixedCells" as="element()*"/>
  <xsl:param name="pEmptyCells" as="element()*"/>
  <xsl:param name="pallFillers" as="element()*"/>

  <xsl:choose>
   <xsl:when test="empty($pEmptyCells)">
      <xsl:sequence select="f:printBoard($pFixedCells)"/>
   </xsl:when>
   <xsl:otherwise>

    <xsl:variable name="vreducedFillers" select=
     "f:reduceFillersByRules($pallFillers)"
     />

		 <xsl:if test="f:canContinue($pFixedCells, $pEmptyCells,
$vreducedFillers)">
			 <xsl:variable name="vBestCell" select=
			     "f:bestCellToTry($pEmptyCells,$vreducedFillers)"/>
      <xsl:variable name="vcellFillers" as="element()*"
        select="f:cellFillers($vreducedFillers,$vBestCell)"/>

          <xsl:sequence select=
            "f:tryFillers($pFixedCells,$pEmptyCells, $vreducedFillers,
                          $vcellFillers,$vBestCell)"
            />
     </xsl:if>
   </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:canContinue" as="xs:boolean">
  <xsl:param name="pFixedCells" as="element()*"/>
  <xsl:param name="pEmptyCells" as="element()*"/>
  <xsl:param name="pallFillers" as="element()*"/>

  <xsl:variable name="vallSingleFillers" as="element()*" select=
  "f:getSingleFillers($pallFillers, $pEmptyCells)"
  />
  <xsl:sequence select=
     "if(empty(
               for $i in 1 to 9
                 return
                   $i[f:hasDuplicates(
                                  f:row($vallSingleFillers,$i)/@val
                                      )
                     or
                      f:hasDuplicates(
                                  f:column($vallSingleFillers,$i)/@val
                                      )
                     or
                      f:hasDuplicates(
                                  f:staticRegion($vallSingleFillers,$i)/@val
                                      )
                      ]
               )
          )
          then
	          true() (:
empty($pEmptyCells[empty(f:cellFillers($pallFillers,.))]) :)
	         else
	          false()

     "/>
<!-- -->
</xsl:function>

<xsl:function name="f:getSingleFillers" as="element()*">
  <xsl:param name="pallFillers" as="element()*"/>
  <xsl:param name="pEmptyCells" as="element()*"/>

  <xsl:for-each select="$pEmptyCells">
   <xsl:variable name="vtheFillers"
     select="f:cellFillers($pallFillers,.)"/>

     <xsl:sequence select=
       "if(not($vtheFillers[2]))
          then $vtheFillers[1]
          else ()
       "
       />
 </xsl:for-each>
</xsl:function>

<xsl:function name="f:hasDuplicates" as="xs:boolean">
 <xsl:param name="pSeq" as="item()*"/>

 <xsl:sequence select="count(distinct-values($pSeq)) ne count($pSeq)"/>



</xsl:function>



<xsl:function name="f:cellFillers" as="element()*">
  <xsl:param name="pallFillers" as="element()*"/>
  <xsl:param name="pemptyCell" as="element()"/>

  <xsl:sequence select="$pallFillers[@row eq $pemptyCell/@row
                                    and
                                     @col eq $pemptyCell/@col
                                    ]"/>

</xsl:function>



<xsl:function name="f:bestCellToTry" as="element()?">
  <xsl:param name="pEmptyCells" as="element()*"/>
  <xsl:param name="pallFillers" as="element()*"/>

  <xsl:for-each-group select="$pEmptyCells"
   group-by="count(f:cellFillers($pallFillers,.))">
   <xsl:sort select="current-grouping-key()" order="ascending"/>

   <xsl:if test="position() = 1">
    <xsl:sequence select="current-group()[1]"/>
   </xsl:if>
  </xsl:for-each-group>
</xsl:function>

<xsl:function name="f:makeFillers" as="element()*">
 <xsl:param name="pFixedCells" as="element()*"/>
 <xsl:param name="pEmptyCells" as="element()*"/>

 <xsl:sequence select="$pEmptyCells/f:makeFillersForCell($pFixedCells,.)"/>
</xsl:function>

<xsl:function name="f:makeFillersForCell" as="element()*">
 <xsl:param name="pFixedCells" as="element()*"/>
 <xsl:param name="pEmptyCell" as="element()"/>

   <xsl:for-each select="$vAllVals">
     <xsl:if test="not(. = f:column($pFixedCells,$pEmptyCell/@col)/@val)
                 and
                   not(. = f:row($pFixedCells,$pEmptyCell/@row)/@val)
                 and
                   not(. = f:region($pFixedCells, $pEmptyCell)/@val)
                  ">
		    <xsl:sequence
select="f:makeCell($pEmptyCell/@row,$pEmptyCell/@col,.)"/>
     </xsl:if>
   </xsl:for-each>
</xsl:function>

<xsl:function name="f:tryFillers" as="item()*">
 <xsl:param name="pFixedCells" as="element()*"/>
 <xsl:param name="pEmptyCells" as="element()*"/>
 <xsl:param name="pallFillers" as="element()*"/>
 <xsl:param name="pFillers" as="element()*"/>
 <xsl:param name="pBestCell" as="element()"/>

 <xsl:if test="exists($pFillers)">
  <xsl:variable name="vtheFiller" select="$pFillers[1]"/>

  <xsl:variable name="vreducedFilllers" as="element()*"
   select="f:reduceAllFillers($pallFillers, $pBestCell,$vtheFiller)"/>

  <xsl:variable name="vSolution" select=
  "f:sudoku(($pFixedCells,$vtheFiller),$pEmptyCells[not(. is $pBestCell)],
            $vreducedFilllers
            )
  "/>

    <xsl:choose>
      <xsl:when test="exists($vSolution)">
				 <xsl:sequence select="$vSolution"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select=
        "f:tryFillers($pFixedCells,$pEmptyCells, $pallFillers,
                      subsequence($pFillers,2),$pBestCell)"/>
      </xsl:otherwise>
    </xsl:choose>
 </xsl:if>
</xsl:function>

<xsl:function name="f:reduceFillersByRules" as="element()*">
 <xsl:param name="pFillers" as="element()*"/>

		<xsl:variable name="vSingleFillers" as="element()*">
	    <xsl:for-each select="f:row(), f:column(), f:staticRegion()">
	      <xsl:variable name="vcurgroupFun" select="."/>

		    <xsl:for-each select="1 to 9">
		      <xsl:variable name="vthisGroupFillers"
		          select="f:apply($vcurgroupFun,$pFillers, .)"/>

		      <xsl:for-each-group select="$vthisGroupFillers"
		           group-by="@val"
		      >
		        <xsl:sort select="count(current-group())"/>

		        <xsl:if test="not(current-group()[2])">
		         <xsl:sequence select="current-group()[1]"/>
          </xsl:if>
		      </xsl:for-each-group>
		    </xsl:for-each>
	    </xsl:for-each>
   </xsl:variable>

   <xsl:sequence select=
    "for $filler in $pFillers
       return
          if(not(exists($vSingleFillers
                         [not(. is $filler)
                         and
                          @row=$filler/@row
                         and
                          @col=$filler/@col
                          ]
                       )
                )
             )
          then $filler
          else ()
    "/>
</xsl:function>

<xsl:function name="f:reduceAllFillers" as="element()*">
 <xsl:param name="pallFillers" as="element()*"/>
 <xsl:param name="ppickedCell" as="element()"/>
 <xsl:param name="pthisFiller" as="element()"/>

 <xsl:sequence select=
 "$pallFillers[(@row ne $ppickedCell/@row
               or
                @col ne $ppickedCell/@col
                 )
               and
                (
	                if(@row = $ppickedCell/@row
	                   or
	                    @col = $ppickedCell/@col
	                   or
	                     (
	                      ((@row - 1) idiv 3 eq ($ppickedCell/@row -1) idiv 3)
	                     and
	                       ((@col - 1) idiv 3 eq ($ppickedCell/@col -1) idiv 3)
	                      )
	                    )
	                    then
	                      @val ne $pthisFiller/@val
	                    else
	                      true()
                 )
                ]
  "
  />
</xsl:function>

<xsl:variable name="vfunRow" as="element()">
  <f:row/>
</xsl:variable>

<xsl:template match="f:row" mode="f:FXSL" as="element()*">
  <xsl:param name="arg1" as="element()*"/>
  <xsl:param name="arg2" as="xs:integer"/>

  <xsl:sequence select="f:row($arg1,$arg2)"/>
</xsl:template>

<xsl:function name="f:row" as="element()">
  <xsl:sequence select="$vfunRow"/>
</xsl:function>

<xsl:variable name="vfunColumn" as="element()">
  <f:column/>
</xsl:variable>

<xsl:template match="f:column" mode="f:FXSL" as="element()*">
  <xsl:param name="arg1" as="element()*"/>
  <xsl:param name="arg2" as="xs:integer"/>

  <xsl:sequence select="f:column($arg1,$arg2)"/>
</xsl:template>

<xsl:function name="f:column" as="element()">
  <xsl:sequence select="$vfunColumn"/>
</xsl:function>

<xsl:variable name="vfunStatRegion" as="element()">
  <f:staticRegion/>
</xsl:variable>

<xsl:template match="f:staticRegion" mode="f:FXSL" as="element()*">
  <xsl:param name="arg1" as="element()*"/>
  <xsl:param name="arg2" as="xs:integer"/>

  <xsl:sequence select="f:staticRegion($arg1,$arg2)"/>
</xsl:template>

<xsl:function name="f:staticRegion" as="element()">
  <xsl:sequence select="$vfunStatRegion"/>
</xsl:function>

<xsl:function name="f:column" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="pColno" as="xs:integer"/>

  <xsl:sequence select="$pCells[@col = $pColno]"/>
</xsl:function>

<xsl:function name="f:row" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="pRowno" as="xs:integer"/>

  <xsl:sequence select="$pCells[@row = $pRowno]"/>
</xsl:function>

<xsl:function name="f:region" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="paCell" as="element()"/>

  <xsl:variable name="vregRowStart" as="xs:integer"
       select="3*(($paCell/@row -1) idiv 3) +1"/>
  <xsl:variable name="vregColStart" as="xs:integer"
       select="3*(($paCell/@col -1) idiv 3) +1"/>

  <xsl:sequence select=
     "$pCells[xs:integer(@row) ge $vregRowStart and xs:integer(@row)
lt ($vregRowStart +3)
				    and
				 	    xs:integer(@col) ge $vregColStart and xs:integer(@col) lt
($vregColStart +3)
             ]"/>
</xsl:function>

<xsl:variable name="vRegdata" as="element()+">
  <reg rstart="1" colstart="1"/>
  <reg rstart="1" colstart="4"/>
  <reg rstart="1" colstart="7"/>
  <reg rstart="4" colstart="1"/>
  <reg rstart="4" colstart="4"/>
  <reg rstart="4" colstart="7"/>
  <reg rstart="7" colstart="1"/>
  <reg rstart="7" colstart="4"/>
  <reg rstart="7" colstart="7"/>
</xsl:variable>

<xsl:function name="f:staticRegion" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="pRegNo" as="xs:integer"/>

  <xsl:variable name="vregRowStart" as="xs:integer?"
       select="xs:integer($vRegdata[$pRegNo]/@rstart)"/>
  <xsl:variable name="vregColStart" as="xs:integer?"
       select="xs:integer($vRegdata[$pRegNo]/@colstart)"/>

  <xsl:sequence select=
   "$pCells[xs:integer(@row) ge $vregRowStart and xs:integer(@row) lt
($vregRowStart + 3)
           and
							xs:integer(@col) ge $vregColStart and xs:integer(@col) lt
($vregColStart + 3)
           ]"
   />

</xsl:function>



<xsl:function name="f:printBoard">
 <xsl:param name="pCells" as="element()+"/>

 <xsl:for-each-group select="$pCells" group-by="@row">
   <xsl:sort select="current-grouping-key()"/>
   <row>
      <xsl:for-each select="current-group()">
        <xsl:sort select="@col"/>
        <xsl:value-of select=
         "concat(@val, if(position() ne last()) then ', ' else ())"
         />
      </xsl:for-each>
   </row>
 </xsl:for-each-group>
</xsl:function>
</xsl:stylesheet>


sudoku5.xsl:
=========
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f xs">

<xsl:import href="func-apply.xsl"/>



<xsl:output omit-xml-declaration="yes" indent="yes"/>



<xsl:template match="/">



 <xsl:variable name="vFixed" select="f:cellsGroup('Fixed', /*/*)"/>
 <xsl:variable name="vEmpty" select="f:cellsGroup('Empty', /*/*)"/>

 <xsl:variable name="vallFillers" as="element()*">
	  <xsl:for-each select=
	   "f:makeFillers(f:cellsGroup('Fixed', /*/*), f:cellsGroup('Empty',
/*/*))">
	    <xsl:sort select="@row"/>
	    <xsl:sort select="@col"/>

	    <xsl:sequence select="."/>
	  </xsl:for-each>
 </xsl:variable>

  <xsl:sequence
    select="f:sudoku($vFixed, $vEmpty, $vallFillers)"/>
</xsl:template>

<xsl:variable name="vAllVals" select="1 to 9" as="xs:integer+"/>



<xsl:function name="f:cellsGroup" as="element()*">
  <xsl:param name="pgrpType" as="xs:string"/>
  <xsl:param name="pRows" as="element()*"/>
    <xsl:sequence select=
     "for $i in 1 to count($pRows),
           $vRow in $pRows[$i],
               $vNum in tokenize($vRow, ',')
                          [if($pgrpType='Fixed')
                              then . ne '0'
                              else . eq '0'
                          ][if($pgrpType='Empty')
                              then 1
                              else true()],
               $k in index-of(tokenize($vRow, ','),$vNum)
              return
                f:makeCell($i,$k, xs:integer($vNum))
     "/>
</xsl:function>

<xsl:function name="f:makeCell" as="element()">
 <xsl:param name="pnRow" as="xs:integer"/>
 <xsl:param name="pnCol" as="xs:integer"/>
 <xsl:param name="pnVal" as="xs:integer"/>

 <cell row="{$pnRow}" col="{$pnCol}" val="{$pnVal}"/>
</xsl:function>

<xsl:function name="f:sudoku" as="item()*">
  <xsl:param name="pFixedCells" as="element()*"/>
  <xsl:param name="pEmptyCells" as="element()*"/>
  <xsl:param name="pallFillers" as="element()*"/>

  <xsl:choose>
   <xsl:when test="empty($pEmptyCells)">
      <xsl:sequence select="f:printBoard($pFixedCells)"/>
   </xsl:when>
   <xsl:otherwise>

		 <xsl:if test="f:canContinue($pFixedCells, $pEmptyCells, $pallFillers)">
			 <xsl:variable name="vBestCell" select=
			     "f:bestCellToTry($pEmptyCells,$pallFillers)"/>

      <xsl:variable name="vcellFillers" as="element()*"
        select="f:cellFillers($pallFillers,$vBestCell)"/>

          <xsl:sequence select=
            "f:tryFillers($pFixedCells,$pEmptyCells, $pallFillers,
                          $vcellFillers,$vBestCell)"
            />
     </xsl:if>
   </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="f:canContinue" as="xs:boolean">
  <xsl:param name="pFixedCells" as="element()*"/>
  <xsl:param name="pEmptyCells" as="element()*"/>
  <xsl:param name="pallFillers" as="element()*"/>

  <xsl:variable name="vallSingleFillers" as="element()*" select=
  "f:getSingleFillers($pallFillers, $pEmptyCells)"
  />
  <xsl:sequence select=
     "if(empty(
               for $i in 1 to 9
                 return
                   $i[f:hasDuplicates(
                                  f:row($vallSingleFillers,$i)/@val
                                      )
                     or
                      f:hasDuplicates(
                                  f:column($vallSingleFillers,$i)/@val
                                      )
                     or
                      f:hasDuplicates(
                                  f:staticRegion($vallSingleFillers,$i)/@val
                                      )
                      ]
               )
          )
          then
	          true() (:
empty($pEmptyCells[empty(f:cellFillers($pallFillers,.))]) :)
	         else
	          false()

     "/>
</xsl:function>

<xsl:function name="f:getSingleFillers" as="element()*">
  <xsl:param name="pallFillers" as="element()*"/>
  <xsl:param name="pEmptyCells" as="element()*"/>

  <xsl:for-each select="$pEmptyCells">
   <xsl:variable name="vtheFillers"
     select="f:cellFillers($pallFillers,.)"/>

     <xsl:sequence select=
       "if(not($vtheFillers[2]))
          then $vtheFillers[1]
          else ()
       "
       />
 </xsl:for-each>
</xsl:function>

<xsl:function name="f:hasDuplicates" as="xs:boolean">
 <xsl:param name="pSeq" as="item()*"/>

 <xsl:sequence select="count(distinct-values($pSeq)) ne count($pSeq)"/>



</xsl:function>



<xsl:function name="f:cellFillers" as="element()*">
  <xsl:param name="pallFillers" as="element()*"/>
  <xsl:param name="pemptyCell" as="element()"/>

  <xsl:sequence select="$pallFillers[@row eq $pemptyCell/@row
                                    and
                                     @col eq $pemptyCell/@col
                                    ]"/>

</xsl:function>



<xsl:function name="f:bestCellToTry" as="element()?">
  <xsl:param name="pEmptyCells" as="element()*"/>
  <xsl:param name="pallFillers" as="element()*"/>

  <xsl:for-each-group select="$pEmptyCells"
   group-by="count(f:cellFillers($pallFillers,.))">
   <xsl:sort select="current-grouping-key()" order="ascending"/>

   <xsl:if test="position() = 1">
    <xsl:sequence select="current-group()[1]"
     />
   </xsl:if>
  </xsl:for-each-group>
</xsl:function>

<xsl:function name="f:makeFillers" as="element()*">
 <xsl:param name="pFixedCells" as="element()*"/>
 <xsl:param name="pEmptyCells" as="element()*"/>

 <xsl:sequence select="$pEmptyCells/f:makeFillersForCell($pFixedCells,.)"/>
</xsl:function>

<xsl:function name="f:makeFillersForCell" as="element()*">
 <xsl:param name="pFixedCells" as="element()*"/>
 <xsl:param name="pEmptyCell" as="element()"/>

   <xsl:for-each select="$vAllVals">
     <xsl:if test="not(. = f:column($pFixedCells,$pEmptyCell/@col)/@val)
                 and
                   not(. = f:row($pFixedCells,$pEmptyCell/@row)/@val)
                 and
                   not(. = f:region($pFixedCells, $pEmptyCell)/@val)
                  ">
		    <xsl:sequence
select="f:makeCell($pEmptyCell/@row,$pEmptyCell/@col,.)"/>
     </xsl:if>
   </xsl:for-each>
</xsl:function>

<xsl:function name="f:tryFillers" as="item()*">
 <xsl:param name="pFixedCells" as="element()*"/>
 <xsl:param name="pEmptyCells" as="element()*"/>
 <xsl:param name="pallFillers" as="element()*"/>
 <xsl:param name="pFillers" as="element()*"/>
 <xsl:param name="pBestCell" as="element()"/>

 <xsl:if test="exists($pFillers)">
  <xsl:variable name="vtheFiller" select="$pFillers[1]"/>

  <xsl:variable name="vreducedFilllers" as="element()*"
   select="f:reduceAllFillers($pallFillers, $pBestCell,$vtheFiller)"/>

  <xsl:variable name="vreducedFillers2" select=
     "f:reduceFillersByRules($vreducedFilllers)"
     />


  <xsl:variable name="vSolution" select=
  "f:sudoku(($pFixedCells,$vtheFiller),$pEmptyCells[not(. is $pBestCell)],
            $vreducedFillers2
            )
  "/>

    <xsl:choose>
      <xsl:when test="exists($vSolution)">
				 <xsl:sequence select="$vSolution"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select=
        "f:tryFillers($pFixedCells,$pEmptyCells, $pallFillers,
                      subsequence($pFillers,2),$pBestCell)"/>
      </xsl:otherwise>
    </xsl:choose>
 </xsl:if>
</xsl:function>

<xsl:function name="f:reduceFillersByRules" as="element()*">
 <xsl:param name="pFillers" as="element()*"/>

   <!--f:reduceAllFillers($pallFillers, $pBestCell,$vtheFiller) -->



		<xsl:variable name="vSingleValueFillers" as="element()*">
	    <xsl:for-each select="f:row(), f:column(), f:staticRegion()">
	      <xsl:variable name="vcurgroupFun" select="."/>

		    <xsl:for-each select="1 to 9">
		      <xsl:variable name="vthisGroupFillers"
		          select="f:apply($vcurgroupFun,$pFillers, .)"/>

		      <xsl:for-each-group select="$vthisGroupFillers"
		           group-by="@val"
		      >
		        <xsl:sort select="count(current-group())"/>

		        <xsl:if test="not(current-group()[2])">
		         <xsl:sequence select="current-group()[1]"/>
          </xsl:if>
		      </xsl:for-each-group>
		    </xsl:for-each>
	    </xsl:for-each>
   </xsl:variable>

		<xsl:variable name="vreducedFillers2" as="element()*"
    select=
    "for $filler in $pFillers
       return
          if(not(exists($vSingleValueFillers
                         [not(. is $filler)
                         and
                          @row=$filler/@row
                         and
                          @col=$filler/@col
                          ]
                       )
                )
             )
          then $filler
          else ()
    "/>

    <xsl:sequence select="$vreducedFillers2"/>
<!--
   <xsl:variable name="vSingleFillers" as="element()*">
      <xsl:for-each-group select="$vreducedFillers2"
        group-by="concat(@row,@col)"
      >
       <xsl:sequence select=
        "if(not(current-group()[2]))
           then current-group()[1]
           else ()
        "/>
      </xsl:for-each-group>
   </xsl:variable>

   <xsl:variable name="vreducedFillers1" as="element()*"
    select=
    "for $filler in $vreducedFillers2
       return
          if(not(exists($vSingleFillers
                         [not(. is $filler)
                         and
                          @val = $filler/@val
                         and
                          (@row=$filler/@row
                          or
                           @col=$filler/@col
                          or
                            ( ((@row -1) idiv 3 eq ($filler/@row -1) idiv 3)
                             and
                              ((@col -1) idiv 3 eq ($filler/@col -1) idiv 3)
                             )
                           )
                          ]
                       )
                )
             )
          then $filler
          else ()
    "
    />
    <xsl:sequence select="$vreducedFillers1"/>
-->
<!--
    <xsl:sequence select=
     "if(count($vreducedFillers2) eq count($pFillers))
      then
        $vreducedFillers2
      else
				 f:reduceFillersByRules($vreducedFillers2)
     "
     />
-->
</xsl:function>

<xsl:function name="f:reduceAllFillers" as="element()*">
 <xsl:param name="pallFillers" as="element()*"/>
 <xsl:param name="ppickedCell" as="element()"/>
 <xsl:param name="pthisFiller" as="element()"/>

 <xsl:sequence select=
 "$pallFillers[(@row ne $ppickedCell/@row
               or
                @col ne $ppickedCell/@col
                 )
               and
                (
	                if(@row = $ppickedCell/@row
	                   or
	                    @col = $ppickedCell/@col
	                   or
	                     (
	                      ((@row - 1) idiv 3 eq ($ppickedCell/@row -1) idiv 3)
	                     and
	                       ((@col - 1) idiv 3 eq ($ppickedCell/@col -1) idiv 3)
	                      )
	                    )
	                    then
	                      @val ne $pthisFiller/@val
	                    else
	                      true()
                 )
                ]
  "
  />
</xsl:function>

<xsl:variable name="vfunRow" as="element()">
  <f:row/>
</xsl:variable>

<xsl:template match="f:row" mode="f:FXSL" as="element()*">
  <xsl:param name="arg1" as="element()*"/>
  <xsl:param name="arg2" as="xs:integer"/>

  <xsl:sequence select="f:row($arg1,$arg2)"/>
</xsl:template>

<xsl:function name="f:row" as="element()">
  <xsl:sequence select="$vfunRow"/>
</xsl:function>

<xsl:variable name="vfunColumn" as="element()">
  <f:column/>
</xsl:variable>

<xsl:template match="f:column" mode="f:FXSL" as="element()*">
  <xsl:param name="arg1" as="element()*"/>
  <xsl:param name="arg2" as="xs:integer"/>

  <xsl:sequence select="f:column($arg1,$arg2)"/>
</xsl:template>

<xsl:function name="f:column" as="element()">
  <xsl:sequence select="$vfunColumn"/>
</xsl:function>

<xsl:variable name="vfunStatRegion" as="element()">
  <f:staticRegion/>
</xsl:variable>

<xsl:template match="f:staticRegion" mode="f:FXSL" as="element()*">
  <xsl:param name="arg1" as="element()*"/>
  <xsl:param name="arg2" as="xs:integer"/>

  <xsl:sequence select="f:staticRegion($arg1,$arg2)"/>
</xsl:template>

<xsl:function name="f:staticRegion" as="element()">
  <xsl:sequence select="$vfunStatRegion"/>
</xsl:function>

<xsl:function name="f:column" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="pColno" as="xs:integer"/>

  <xsl:sequence select="$pCells[@col = $pColno]"/>
</xsl:function>

<xsl:function name="f:row" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="pRowno" as="xs:integer"/>

  <xsl:sequence select="$pCells[@row = $pRowno]"/>
</xsl:function>

<xsl:function name="f:region" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="paCell" as="element()"/>

  <xsl:variable name="vregRowStart" as="xs:integer"
       select="3*(($paCell/@row -1) idiv 3) +1"/>
  <xsl:variable name="vregColStart" as="xs:integer"
       select="3*(($paCell/@col -1) idiv 3) +1"/>

  <xsl:sequence select=
     "$pCells[xs:integer(@row) ge $vregRowStart and xs:integer(@row)
lt ($vregRowStart +3)
				    and
				 	    xs:integer(@col) ge $vregColStart and xs:integer(@col) lt
($vregColStart +3)
             ]"/>
</xsl:function>

<xsl:variable name="vRegdata" as="element()+">
  <reg rstart="1" colstart="1"/>
  <reg rstart="1" colstart="4"/>
  <reg rstart="1" colstart="7"/>
  <reg rstart="4" colstart="1"/>
  <reg rstart="4" colstart="4"/>
  <reg rstart="4" colstart="7"/>
  <reg rstart="7" colstart="1"/>
  <reg rstart="7" colstart="4"/>
  <reg rstart="7" colstart="7"/>
</xsl:variable>

<xsl:function name="f:staticRegion" as="element()*">
  <xsl:param name="pCells" as="element()*"/>
  <xsl:param name="pRegNo" as="xs:integer"/>

  <xsl:variable name="vregRowStart" as="xs:integer?"
       select="xs:integer($vRegdata[$pRegNo]/@rstart)"/>
  <xsl:variable name="vregColStart" as="xs:integer?"
       select="xs:integer($vRegdata[$pRegNo]/@colstart)"/>

  <xsl:sequence select=
   "$pCells[xs:integer(@row) ge $vregRowStart and xs:integer(@row) lt
($vregRowStart + 3)
           and
							xs:integer(@col) ge $vregColStart and xs:integer(@col) lt
($vregColStart + 3)
           ]"
   />

</xsl:function>



<xsl:function name="f:printBoard">
 <xsl:param name="pCells" as="element()+"/>

 <xsl:for-each-group select="$pCells" group-by="@row">
   <xsl:sort select="current-grouping-key()"/>
   <row>
      <xsl:for-each select="current-group()">
        <xsl:sort select="@col"/>
        <xsl:value-of select=
         "concat(@val, if(position() ne last()) then ', ' else ())"
         />
      </xsl:for-each>
   </row>
 </xsl:for-each-group>
</xsl:function>
</xsl:stylesheet>






--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.






On 5/2/06, andrew welch <andrew.j.welch@xxxxxxxxx> wrote:
For those of you interested in this I've now finished performance
tuning my Sudoku solution.

I'm quite pleased with it - boards that were taking 15mins+ now take
less than a few seconds.  The most pleasing aspect is the way it
selects the allowed values for a cell - it's much better at detecting
when there's only one possible value, and the way it works through the
board.

I'm also making much more use of subsequence() - several seconds were
shaved off after constructing new sequences from existings sequences
using this function.

I'm satisfied that it's complete now, but if anyone can improve it or
break it, please let me know

It's available here: http://ajwelch.blogspot.com/



cheers
andrew


transparent
Print
Mail
Like It
Disclaimer
.

These Archives are provided for informational purposes only and have been generated directly from the Altova mailing list archive system and are comprised of the lists set forth on www.altova.com/list/index.html. Therefore, Altova does not warrant or guarantee the accuracy, reliability, completeness, usefulness, non-infringement of intellectual property rights, or quality of any content on the Altova Mailing List Archive(s), regardless of who originates that content. You expressly understand and agree that you bear all risks associated with using or relying on that content. Altova will not be liable or responsible in any way for any content posted including, but not limited to, any errors or omissions in content, or for any losses or damage of any kind incurred as a result of the use of or reliance on any content. This disclaimer and limitation on liability is in addition to the disclaimers and limitations contained in the Website Terms of Use and elsewhere on the site.

.
.

transparent

transparent