On 7 October 2017 at 21:29, oldk1331 <[email protected]> wrote:
> About the "Maybe Maybe X" problem:
>
> Since Waldek gives the idea of using GENSYM() to mark failure,
> I want to hear his opinion.
>
> One of my original motives to introduce Maybe is performance,
> the other motive is better abstraction.  Seems we can't have both.

I think we can have both. Your inline optimization is all that is needed.

> If I have to choose between them, I'll choose better abstraction.
>
> If we choose "Rep := List R", then the performance should be
> same as Union(X, "failed").
>

With the current SPAD compiler and your most recent inline
optimizations that does not seem to be true. My benchmark below shows
that "Rep := List R" has almost the same performance for testing
failed and retracting/upwrapping a value as using global GENSYM.
Testing empty?/failed? is actually a little bit faster.
"Union(R,"failed")" on the other hand does seem to take about 80%
longer to unwrap a value.

> I did a simple benchmark on subtractIfCan$NNI, the GENSYM()
> approach can be 12% faster (or 20% faster if a GC happens).
> That may speed up "groebner" by 4%.  I guess if such optimization
> is really needed, it can be done case by case.
>

I recommend that you try your simple benchmark again using "Rep :=
List R". You should get the same performance as with global GENSYM
(notwithstanding a possible increase in GC).

--

wspage@strix ~ $ fricas -nox

(1) -> )r maybe-bench-all
)co fricas-oldk/src/algebra/maybe.spad

   Compiling FriCAS source code from file
      /home/wspage/fricas-oldk/src/algebra/maybe.spad using old system
      compiler.
   MAYBE abbreviates domain Maybe
------------------------------------------------------------------------
   Maybe is now explicitly exposed in frame frame1
   Maybe will be automatically loaded when needed from
      /home/wspage/MAYBE.NRLIB/MAYBE

)co maybe-bench-oldk

   Compiling FriCAS source code from file
      /home/wspage/maybe-bench-oldk.spad using old system compiler.
   TESTM abbreviates package TestMaybe
------------------------------------------------------------------------
   TestMaybe is now explicitly exposed in frame frame1
   TestMaybe will be automatically loaded when needed from
      /home/wspage/TESTM.NRLIB/TESTM

)set message type off

f1 1;


)time on

-- using Maybe(R) with Rep:=R and global GENSYM() to mark failure
-- testing failed?
f1 200;


                                                   Time: 0.47 (EV) = 0.47 sec
-- unwarp
g1 200;


                                                   Time: 0.39 (EV) = 0.39 sec
--
-- using Maybe(R) with Rep:=R and local GENSYM() to mark failure
-- testing failed2?
f2 200;


                                                   Time: 1.20 (EV) = 1.20 sec
--
-- using Union(R,"failed")
-- testing case "failed"
f3 200;


                                                   Time: 0.44 (EV) = 0.44 sec
-- coerce to R
g3 200;


                           Time: 0.00 (IN) + 0.70 (EV) + 0.00 (OT) = 0.71 sec
)time off

)co maybe.spad

   Compiling FriCAS source code from file /home/wspage/maybe.spad using
      old system compiler.
   MAYBE abbreviates domain Maybe
------------------------------------------------------------------------
   Maybe is already explicitly exposed in frame frame1
   Maybe will be automatically loaded when needed from
      /home/wspage/MAYBE.NRLIB/MAYBE


)co maybe-bench4

   Compiling FriCAS source code from file
      /home/wspage/maybe-bench4.spad using old system compiler.
   TESTM4 abbreviates package TestMaybe4
------------------------------------------------------------------------
   TestMaybe4 is now explicitly exposed in frame frame1
   TestMaybe4 will be automatically loaded when needed from
      /home/wspage/TESTM4.NRLIB/TESTM4

f4 1;


)time on

-- using Maybe(R) with Rep:=List R
-- testing empty?
f4 200;


                                                   Time: 0.38 (EV) = 0.38 sec
-- retract
g4 200;


                                                   Time: 0.43 (EV) = 0.43 sec


-- file: maybe-bench-all.input
)co fricas-oldk/src/algebra/maybe.spad
)co maybe-bench-oldk
)set message type off
f1 1;
)time on
-- using Maybe(R) with Rep:=R and global GENSYM() to mark failure
-- testing failed?
f1 200;
-- unwarp
g1 200;
--
-- using Maybe(R) with Rep:=R and local GENSYM() to mark failure
-- testing failed2?
f2 200;
--
-- using Union(R,"failed")
-- testing case "failed"
f3 200;
-- coerce to R
g3 200;
)time off
)co maybe.spad
)co maybe-bench4
f4 1;
)time on
-- using Maybe(R) with Rep:=List R
-- testing empty?
f4 200;
-- retract
g4 200;
--

-- file: maybe-bench-oldk.spad
--- Maybe benchmark package
)abbrev package TESTM TestMaybe
TestMaybe() : Exp == Imp where
   Exp == with
     f1 : Integer -> Integer
     g1 : Integer -> Integer
     f2 : Integer -> Integer
     f3 : Integer -> Integer
     g3 : Integer -> Integer
   Imp == add
     NNI ==> NonNegativeInteger
     import from Vector NNI
     v1 : Vector Maybe NNI := new(10^6, failed())
     v2 : Vector Union(NNI, "failed") := new(10^6, "failed")
     w1 : Vector Maybe NNI := [wrap i for i in 1..10^6]
     w2 : Vector Union(NNI, "failed") := [i for i in 1..10^6]

     f1 x ==
         v := v1
         for j in 1..x repeat
           for i in 1..10^6 repeat
             failed? qelt(v, i)
         x

     g1 x ==
         w := w1
         for j in 1..x repeat
           for i in 1..10^6 repeat
             unwrap! qelt(w, i)
         x

     f2 x ==
         v := v1
         for j in 1..x repeat
           for i in 1..10^6 repeat
             failed2? qelt(v, i)
         x

     f3 x ==
         v := v2
         for j in 1..x repeat
           for i in 1..10^6 repeat
             qelt(v, i) case "failed"
         x

     g3 x ==
         w := w2
         for j in 1..x repeat
           for i in 1..10^6 repeat
             qelt(w, i)::NNI
         x
--

-- file: maybe-bench4.spad
--- Maybe benchmark package
)abbrev package TESTM4 TestMaybe4
TestMaybe4() : Exp == Imp where
   Exp == with
     f4 : Integer -> Integer
     g4 : Integer -> Integer
   Imp == add
     NNI ==> NonNegativeInteger
     import from Vector NNI

     v4 : Vector Maybe NNI := new(10^6, empty())
     w4 : Vector Maybe NNI := [coerce i for i in 1..10^6]

     f4 x ==
         v := v4
         for j in 1..x repeat
           for i in 1..10^6 repeat
             empty? qelt(v, i)
         x

     g4 x ==
         w := w4
         for j in 1..x repeat
           for i in 1..10^6 repeat
             qretract qelt(w, i)
         x
--

-- file: maybe.spad
)abbrev domain MAYBE Maybe
++ Description:
++ The type Maybe(R) represents either a value of type R, or absence/failure.
++ Using Maybe is a good way to deal with errors or exceptional cases without
++ resorting to drastic measures such as error.  It replaces the usage of
++ Union(R, "failed").

Maybe(R : Type) : Exports == Implementation where
  Exports == RetractableTo(R) with
      construct : R -> %
      coerce : List R -> %
      empty : () -> %
          ++ empty() returns a value that indicates failure.
      empty? : % -> Boolean
          ++ empty?(x) checks if x is empty().
      retractable? : % -> Boolean
          ++ retractable?(x) checks if x is of type R.
      qretract : % -> R
          ++ fast retract (no test for empty)
      maybe : (%, R) -> R
          ++ maybe(x, default) returns x as type R if it's not empty(),
          ++ otherwise returns default.
      maybe : (R -> R, %, R) -> R
          ++ maybe(f,x,default) returns f(unwrap x) or default if empty?(x)
      if R has CoercibleTo OutputForm then CoercibleTo OutputForm
      if R has BasicType then BasicType
      if R has SetCategory then SetCategory

  Implementation == add
      Rep := List R
      errMsg ==> "retract: the argument is empty()"

      construct(x) == [x]
      coerce(x) ==
        if #x>1 then error "not singleton"
        x
      empty() == empty()$Rep
      empty? x == empty?(x)$Rep
      coerce(x:R):% == [x]
      retractable? x == not empty?(x)
      retractIfCan x == if empty?(x) then "failed" else first x
      retract x == if empty?(x) then error errMsg else first x
      qretract x == first x
      maybe(x, default) == if empty?(x) then default else first x
      maybe(f,x,default) == if empty?(x) then default else f(first x)

      if R has CoercibleTo OutputForm then
          coerce(x : %) : OutputForm == coerce(x)$Rep

      if R has BasicType then
          x = y == (x = y)$Rep

      if R has SetCategory then
          hashUpdate!(hs : HashState, x : %) == hashUpdate!(hs, x)$Rep
--

Bill Page

-- 
You received this message because you are subscribed to the Google Groups 
"FriCAS - computer algebra system" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/fricas-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to