Version 1.2   (2026-04-29)

   1) New summary S3 method for grpnet and cv.grpnet
	* Computes fitted values and variable importances
	* Print methods also exist for each case

   2) Added keep.data argument to grpnet function
	* New default keeps a copy of the data
	* For fitted values, importances, etc.

   3) Updates to plot.grpnet() and plot.cv.grpnet()
	* xlab = expression(log(lambda)) for all plots
	* Added "cv" argument to plot.cv.grpnet()

   4) Bug fix in predict.grpnet() for single row of newdata
	* Previously caused error when nrow(newdata) = 1
	* Update allows for prediction at single data point

   5) Computational improvements to row.kronecker() function
	* Previously column names were grown inside for loop
	* Update initializes column names and fills in values

   6) Various inconsequential updates for efficiency and readable





Version 1.1   (2026-01-07)

   1) ordinal: new loss function for ordinal classification
	* Implements proportional odds logistic regression (polr)
	* Uses cumulative link model framework:  Prob(Y >= y | X = x)
	* Can be applied to ordered factors or continuous data

   2) Bug fix / improvement for cv.grpnet.default
	* Previously the group labels were replaced by integers
	* Now group labels are retained as in the formula method
	* Allows for simpler comparison between two methods

   3) Bug fix / improvement for coef.cv.grpnet and coef.grpnet
	* previously these S3 methods were unintentionally unregistered
	* now the S3 coef methods for cv.grpnet and grpnet are registered

   4) Bug fix / improvement for type = "importance" in predict methods
	* previously would result in NaN if no terms were active in model
	* caused by dividing by zero to normalize the importance indices
	* now the normalization only happens if there is 1+ active term(s)

   5) Updates and improvements to package documentation
	* corrections to typos / out-of-date text
	* modified / expanded comments throughout




Version 1.0   (2025-06-09)

   1) New loss functions for binary classification
	* logit: alternative implementation of binomial for y in {-1,1}
	* svm2: squared hinge loss function for y in {-1,1}
	* Note: hsvm has been renamed svm1 (see #3 below)

   2) visualize.loss: new function for visualizing loss functions
	* Plots requested grpnet loss versus mu given a particular y
	* Only required input is the name of the family/loss function
	* Optional inputs are x sequence, y value, and plotting specs

   3) New alternative (simpler) names for the two SVM loss functions
	* hsvm   ---->   svm1   (quadratically smoothed hinge loss)
	* sqsvm  ---->   svm2   (squared hinge loss)
	* Old names will be internally converted to new names

   4) Inconsequential changes/updates to family = "hsvm"/"svm1" 
	* R_grpnet_hsvm: Renamed the deviance function
	* grpnet.default: removed unnecessary testR in line 517
	* family documentation: fixed typo (hvsm ---> hsvm)

   5) Improvements to family.grpnet 
	* Previously there was no checking or partial matching allowed
	* Now checks whether input family is valid (after partial matching)
	* Also functions like an S3 method to return family component



Version 0.9   (2025-05-01)

   1) Bug fixes in coef.grpnet()
	* Line 49 caused an error due to using names() instead of rownames()
	* Fixed code uses rownames() to correctly pull multivariate coef names
	* Thanks to Kyra Wilson at University of Washington for finding the bug

   2) Added family = "hsvm" (Huberized support vector machine)
	* Implements the quadratically smoothed hinge loss function
	* Designed for binary classification problems:  y %in% c(-1, 1)
	* Additional argument "theta" controls smoothing rate

   3) plot.grpnet: additions and changes to default
	* New option of "dev.ratio" to plot log(lambda) vs dev.ratio
	* This is the new default type for grpnet's S3 plotting method
	* To get the old default:  plot(mod, type = "coef")




Version 0.8   (2025-03-27)

   1) Bug fixes in cv.grpnet() for "multigaussian" family
	* Fixed argument bug in cv.grpnet.default() with parallel computing
	* Fixed offset dimensions (for cv.grpnet() with offset = NULL)

   2) Bug fixes in grpnet() for "multigaussian" family
	* "grpnet_init.c" contained a typo ---> incorrect memory allocation
	* Fixed argument bug in grpnet.default() with proglang = “R”

   3) Improvements to plot.grpnet() function for multivariate responses.
	* Now plots response dimension names as title (instead of legend)
	* Now uses unique (not common) y-axis limits for each dimension

   4) Updated references for package and help files (Helwig, 2025).




Version 0.7   (2025-01-23)

   1) Bug fix in cv.grpnet() for multinomial when adaptive = TRUE
	* Previously produced an error when orthogonalized = TRUE
	* Error was due to improper handling of listed terms
	* Updated version can now handle orthogonalization

   2) Bug fix in rk() when providing Boundary.knots
	* Previously Boundary.knots were ignored if knots = NULL
	* This could have been problematic for periodic data
	* Now Boundary.knots are used regardless of knots input

   3) Bug fix in convergence handling for all R versions of internals
	* Previously proglang = "R" used different relative convergence
	* This only affected initialization of unpenalized terms
	* Now exact same convergence is used for Fortran and R code

   4) Added "multigaussian" family
	* Used for fitting multivariate gaussian responses models
	* Simultaneous shrinking and selecting of multivariate responses
	* Output is structured similar to that of the multinomial models

   5) Improvements to basis used for nominal (categorical) predictors
	* Previously used a version of dummy coding when use.rk = TRUE
	* Problem: does not guarantee that the coefficients sum to zero
	* Now uses a version of effect coding, ensuring coefs sum to zero

   6) Other miscellaneous updates
	* The used "proglang" is now returned by the grpnet() function
	* Added the "standardize.response" argument to grpnet() function
	* Improvements to intervals of coef, predict, plot, etc.




Version 0.6   (2024-10-11)

   1) Bug fix in rk() function for situations when min(x) = max(x)
	* In this setup, x is a useless predictor (by definition) 
	* Previous defaults would produce NaN error (divide by zero)
	* Updated version can handle predictors with zero variance
   2) Bug fix in grpnet() function for situations when min(x) = max(x)
	* In this setup, x is a useless predictor (by definition) 
	* Previously caused an error when using orthogonalized = TRUE
	* Updated version handles orthogonalization when min(x) = max(x) 
   3) cv.grpnet: new arguments for adaptive estimation of penalty weights
	* adaptive = T/F argument activates adaptive estimation
	* power = exponent used in defining adaptive weights
   4) Changed default "s" value for coef.cv.grpnet
	* Previously used "lambda.min" as default
	* Now uses "lambda.1se" as default
   5) Improvements to internals of cv.grpnet
	* Previously required passing penalty to pass penalty.factor
	* Now it is possible to pass penalty.factor w/o passing penalty



Version 0.5   (2024-07-12)

   1) Bug fix in cv.grpnet() for multinomial response with matrix input
	* Previously could produce NaN (divide by zero) due to normalization
	* Only was a problem when y was a matrix with apply(y, 1, max) > 1
	* Now normalization y / rowSums(y) only happens within grpnet()

   2) Update to default type.measure of cv.grpnet()
	* type.measure = "mae" is the new default for non-categorical responses
	* Use type.measure = "deviance" to obtain the previous default
	* type.measure = "class" is still the default for categorical responses

   3) Improvements to internal Fortran code for adaptive variance bounding
	* Previously used current mu for upper bound, e.g., vmax = max(mu)
	* Now uses the max of current mu and response, e.g., vmax = max(max(mu), max(y))
	* Applies to families: poisson, negative.binomial, inverse.gaussian

   4) New argument to control which programming language is used (Fortran or R)
	* "proglang" argument controls the programming language for internals
	* Default is to use "Fortran" for internals (which is much faster)
	* Using "R" is slower but can be helpful for pedagogical purposes

   5) Improved degrees of freedom definition for multinomial 
	* Previously the df calculation multiplied the result by nresp
	* This ignores the loss of df due to the sum-to-zero constraint 
	* Updated definition multiplies by (nresp-1) to account for loss of df

   6) Added "time" (runtime) to output of cv.grpnet() and grpnet()

   7) Improvements to help files for grpnet and cv.grpnet (and their predict methods)



Version 0.4   (2024-06-05)

   1) Bug fix in rk() - only applicable to odd x distributions
	* Defaults could have produced replicate knots (causing prediction issue)
	* Previous: knots = quantile(x, probs = seq(0, 1, length.out = df))
	* Updated:  knots = unique(quantile(x, probs = seq(0, 1, length.out = df)))

   2) Added cv.compare() function
	* Plots cv-error (+/- sd) for different solutions
	* For a single model, it plots lambda.min and lambda.1se
	* For multiple models, it plots (min, 1se) for all models

   3) Added visualize.penalty() function
	* New function to plot (or return grpnet penalty (or its derivative)
	* Can plot/return the penalty evaluation for different signal strengths 
	* Allows user to adjust hyperparameters that control the penalty

   4) Added visualize.shrink() function
	* New function to plot (or return) grpnet shrinkage (or its fitted values)
	* Can plot/return the shrinkage operator for different signal strengths 
	* Allows user to adjust hyperparameters that control the shrinkage

   5) "character" variables are now supported by formula methods
	* Previously rk.model.matrix failed for characters
	* Now character variables are coerced to factors
	* Applies to cv.grpnet, grpnet, and rk.model.matrix

   6) Update to default gamma used for grpnet()
	* The gamma argument is the hyperparameter for MCP and SCAD
	* Previous default was gamma = 3 for MCP and gamma = 4 for SCAD
	* New default is gamma = 4 for both MCP and SCAD

   7) Update to defaults of standardized and orthogonalized in grpnet()
	* Previous default was to standardize (i.e., standardized = TRUE)
	* New default is to orthogonalize (i.e., orthogonalized = TRUE)
	* In practice, it can be useful to compare both approaches

   8) Updates to defaults of cv.grpnet() tuning
	* Now deviance is defined as the MEAN (not SUM) of deviance residuals
	* Now gamma is tuned with respect to c(3, 4, 5) when using MCP or SCAD
	* Now $tune returns table of tuning results for alpha and gamma

   9) Changes to defaults of predict.cv.grpnet
	* Previously default prediction was at lambda.min
	* New default is to predict at lambda.1se
	* Revert to old default by using:  s = "lambda.min"

  10) Added reference to Helwig (2024) for the ABGD algorithm
	Helwig, N. E. (2024). Versatile descent algorithms for group 
	regularization and variable selection in generalized linear models. 
	Journal of Computational and Graphical Statistics.
	doi: 10.1080/10618600.2024.2362232



Version 0.3   (2024-02-20)

   1) Added orthogonalization option to grpnet
	* Use 'orthogonalize = TRUE' to groupwise orthogonalize design matrices
	* Default is still 'standardize = TRUE' (and 'orthogonalize = FALSE')
	* Now three possible options: unstandardized, standardized, orthogonalized

   2) Improvement to rk() and rk.model.matrix for periodic splines
	* Periodicity is specified via a named list with T/F for each entry 
	* Previously it was necessary to include all variables in list
	* Now any variable excluded from the list automatically gets F entry

   3) Additional output included for grpnet() function
	* New returned value: "xsd" gives the groupwise standard deviation of 'x'
	* The "xsd" values are used to standardize 'x' (when standardize = TRUE)
	* The "xsd" values are used by predict.grpnet() when type = "znorm"

   4) Expanded functionality for predict.grpnet() and predict.cv.grpnet()
	* New prediction type: "znorm" gives L2 norm of standardized coefs
	* Equivalent to multiplying the "norm" type prediction by "xsd"
	* "znorm" should be preferred over "norm" when predictor metrics differ

   5) Inconsequential updates to underlying Fortran code
	* Previously the "pw" argument was only used to input penalty weights
	* Now the "pw" argument is used to output "xsd" (x standard deviation)
	* This output is now returned as a part of grpnet objects ($xsd)

   6) Additional option ("znorm") for plot.grpnet() function

   7) Slight update to package title and description. 

   8) Added an additional reference to rk() and rk.model.matrix() help files



Version 0.2   (2023-09-08)

   1) Bug Fix (penalty.factor)
	* In ver 0.1 penalty.factor was not being passed to internal Fortran routines
	* In the Fortran code, the penalty.factor was hard-coded as sqrt(grpsize)
	* Now the penalty.factor argument is appropriately passed to internal code
   2) Bug Fix (ridge solution)
	* In ver 0.1 the ridge solution was computed at alpha = 0.001 for the first entry
	* Now alpha = 0.001 is used to compute the lambda sequence but not the solution
	* In ver 0.2 the ridge solution is computed at alpha = 0 (using lambda[1] from alpha = 0.001)
   3) Expanded functionality of predict.grpnet and predict.cv.grpnet functions
	* Previously only offered predictions of type "link", "response", and "class"
	* Now offers 11 kinds of predictions (although some are not actually predictions)
	* Additions include "terms", "importance", and 6 options for extracting coefficient info
   4) Expanded functionality of plot.grpnet function
	* Previously only offered plot of coefficient values (colored by group)
	* Now offers three types: coef, norm, imp (obtained via predict.grpnet)
	* The "type" option controls the type of plot that is produced
   5) Improvements to grpnet and cv.grpnet outputs for multinomial responses
	* Previously factor levels were internally replaced with y1,...,ym
	* Resulted in coef names that differed from original factor levels
	* Now original factor levels are retained and used for coef names
   6) Improvements to the formula methods for grpnet and cv.grpnet
	* Previously used model.matrix() to build (parametric) design matrix
	* New argument: "use.rk" controls whether to use model.matrix() or rk.model.matrix()
	* New default: "use.rk = TRUE" uses rk.model.matrix() to build (nonparametric) design matrix
   7) Intercept is now accounted for in "group" that is output of grpnet (and cv.grpnet)
	* Previously the returned "group" was the same regardless of the intercept
	* Now the group vector contains "0" as the first element if an intercept was used
	* Updated behavior is similar to behavior of model.matrix and rk.model.matrix
   8) rk.model.matrix
	* New function for forming model (design) matrices using the rk() function
	* Designed to be a more flexible (nonparametric) alternative to model.matrix
	* Interactions of any order are formed via the row.kronecker function
   9) rk
	* New function for forming a reproducing kernel (smoothing spline) basis
	* Designed to be an improvement of the bs() function in the "stats" package
	* Computes nominal, ordinal, and polynomial (linear, cubic, quintic) splines
  10) row.kronecker
	* New function for computing the row-wise Kronecker product between X and Y
	* Note that X and Y are two matrices with the same number of rows
	* Used by the rk.model.matrix() function to form bases for interaction effects
